Question

I have read a lot of tuts and documentation on form creation and handling in Django but I still am confused on certain aspects of the implementation. Specifically, I cannot understand where I should handle the data sent by the form. Is it on the view that is using the form template or is it on another view?

For example, assume an index template with a single form:

*index.html*
{% load url from future %}
<form action="{% url 'Directories:_results'%}" method="post">
Name: <input type="text" name="txtField" />
<input type="submit" name="submit" />
</form>

So now for my view i have two versions:

#1 version (1 view): The same view displays and handles the form

def index(request):
    if request.method == 'POST': # If the form has been submitted...
        form = dbForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            field = form.cleaned_data['txtField']
            #doSomething
    else:
        form = dbForm() #unbound form
     return render(request, 'Directories/index.html', {'form': form})

#2 version (2 views): One view to display the form and one view to handle the form data

#the view that creates the form (unbound)
def index(request):
    form = dbForm()
    return render(request, 'Directories/index.html', {'form':form})

#the view that handles the data sent during form submission in the index template.
def results(request):
    if request.method == 'POST':
        form = dbForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            field = form.cleaned_data['txtField']
            #doSomething
     else:
         form = dbForm() #unbound form
     return render(request, 'Directories/index.html', {'form': form})

and here is my urls.py:

from django.conf.urls import patterns, url
from Directories import views

urlpatterns = patterns('',
    url(r'^$', views.index, name='_index'),
    url(r'^results$', views.results, name='_results'),)

As you can see data handling is performed differently in each version and as a result I want to know if any of these is wrong and if both are correct then which one is considered the best practice.

Was it helpful?

Solution

Generally a form will post to the same view it is being displayed on.

You can simplify the view logic like so:

def index(request):
    form = dbForm(data=request.POST or None)
    if form.is_valid(): # All validation rules pass
        field = form.cleaned_data['txtField']
        #doSomething
        return redirect(success_url)
    return render(request, 'Directories/index.html', {'form': form})

Note that it is usually good if you redirect after a successful form post, even if you redirect back to the same view. This prevents the user from being prompted to 'resend form data' if they refresh the page.

You should look at the docs for rendering a form in the template:
https://docs.djangoproject.com/en/dev/topics/forms/#looping-over-the-form-s-fields

If you don't render the field errors, for example, the user will never know what the problem was.

An example of a form that would post to a different view is if say your base template has a 'search' form which appears on every page. When you post this form you don't want to come back to the current view, you want to go to the 'search results' view.

OTHER TIPS

Generally, one view corresponds to one url. Also, same url should show the form and accept the submitted form. With this logic, your first approach is better. One view shows and accepts the form.

However, there are cases where view to show form is different than the one accepts it. For example, a page that has multiple forms. Each form can be submitted to different view. But a different view can be implemented to handle that url and show such forms.

There's nothing wrong with either, it depends on what you want to do. By default forms send the data to the same request but you can send the data to a different view if that's more convenient

For most cases it's usually simpler to use the same view. Using two views is good if you're using an external tool\app\whatever or if you want tighten your security (having the second view only accept requests with post data for example etc.), but will require extra steps (error handling, succesful redirect)

The first thing to understand is that the view that processes the form is usually also the one that shows the form in the first place -- because it has to show the form again in case of errors.

In your template, you build the form HTML entirely by hand. That's unusual, because in case of errors (usually a required field that wasn't filled in) you want to render the form again, with all the values already entered present, and with a nice error message. Django's form rendering ( {{ form.as_p }} and the like) do that for you, you don't get it if you write the HTML by hand like this. In fact your view misses an else: clause on the is_valid(), leading it to

So usually the view does both, except for the second thing to understand: after a successful POST, you always redirect to a succes page, or possibly to the same page (which will show an empty form again). Mostly so the user can't accidentally re-submit the form with the refresh button then.

So your 1st is typical, except that you also need to finish with returning a ResponseRedirect in the is_valid() case, and should render more of the form in your template. No need for a second view.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top