Staccato
Staccato

Reputation: 633

Django: Use same view to process same form on two separate pages

I may be overthinking this one or maybe not. I have a registration form that I want to use on the index page and as a standalone form. For some reason, the standalone form works just fine but the form on the index page gives me a 403 error when it's submitted. I will be using jQuery later on, but I need things to also work without JavaScript.

Renders Sign-Up form similar to Facebook homepage

# views.py snippet
class IndexPageTemplateView(TemplateView):  #  index page(http://localhost)
    template_name = 'fld/index.html'

    def get(self, request, *args, **kwargs):
    # prevent logged in users from accessing welcome page
    if self.request.user.is_authenticated():
        return HttpResponse(reverse("member_homepage", args=some_args))
    else:
        return render_to_response(self.template_name)

# Account view

class AccountCreateView(CreateView):  # standalone(http://localhost/signup)
      model = Account
      form_class = CreateAccountForm
      template_name = 'fld2/account_form'
      success_url = 'thanks'

    def get(self, request, *args, **kwargs):
    # prevent logged in users from seeing this form
    if self.request.user.is_authenticated():
        # get the username of logged in user
        ...
        # redirect to homepage
        return HttpResponseRedirect(reverse('some_args', args=(args,)))
    else:
        # display form to non members
        return render(request, self.template_name, {'form': self.get_form_class()})

    def form_valid(self, form):
        clean = form.cleaned_data
        form.instance = form.save()
        if form.instance:
           try:
               # send email
           except Account.DoesNotExist:
           ...
        return super(AccountCreateView, self).form_valid(form)

I'm literally using the same exact forms with different action attributes. I've tried swapping the attribute values, using the same attribute values, and using no attribute values. I can't seem to access my view from the index page at all, even when I hard code it in I get the 403 error. Basically a visitor should be able to register on the homepage(like Facebook) or on the sign-up page( like Twitter). I'm thinking that I might have to use signals to make this work.

http://localhost/

 <!--index.html snippet-->
 <form action="{% url "create_account" %}" method="post">{% csrf_token %}
    <input name="username" type="text" required>
    <input name="password" type="password" required>
    <input name="email" type="email" required>
    <input name="signup1" type="submit" value="Create account">
 </form>

http://localhost/signup

 <!--account_form.html-->
 <form action="." method="post">{% csrf_token %}
    <input name="username" type="text" required>
    <input name="password" type="password" required>
    <input name="email" type="email" required>       
    <input name="signup2" value="Create account" type="submit">
 </form>

main urls.py snippet

url(
    regex=r'^$',
    view=WelcomePageTemplateView.as_view(),
    name='index'
),
url(
    regex=r'^signup$',
    view=include('account.urls'),
    # name='signup'
),
url(
    regex=r'^(?P<slug>[\w]+)/settings/?',
    view=include('account.urls'),
)

account urls.py

url(
    regex=r'^$',
    view=AccountCreateView.as_view(),
    name="create_account"
),

Upvotes: 0

Views: 718

Answers (1)

Alasdair
Alasdair

Reputation: 308779

The {% csrf_token %} tag needs access to the request object in the template. You have used render in your AccountCreateView which includes the request by default, but in your IndexPageTemplateView you have used your render_to_response, which does not.

The easiest way to fix the index view is to use render instead of render_to_response.

def get(self, request, *args, **kwargs):
    # prevent logged in users from accessing welcome page
    if self.request.user.is_authenticated():
        return HttpResponse(reverse("member_homepage", args=some_args))
    else:
        return render(request, self.template_name)

When you override class based views, it's usually a bad idea to override get and post, because you end up duplicating (or breaking) functionality. In your case, it would be better to call super() instead of writing your own code to return a response.

def get(self, request, *args, **kwargs):
    # prevent logged in users from accessing welcome page
    if self.request.user.is_authenticated():
        return HttpResponse(reverse("member_homepage", args=some_args))
    else:
        return super(IndexPageTemplateView, self).get(request, *args, **kwargs)

Upvotes: 2

Related Questions