Alternative to django form processing template?

suggested a template for processing the form in the view, it seems too complicated and not dry for me:

def contact(request): if request.method == 'POST': # If the form has been submitted... form = ContactForm(request.POST) # A form bound to the POST data if form.is_valid(): # All validation rules pass # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/thanks/') # Redirect after POST else: form = ContactForm() # An unbound form return render_to_response('contact.html', { 'form': form, }) 

With a lot of conventions, it repeats the ContactForm () construct, and the whole block repeats wherever the view should process the form. Isn't there a better way to do this?

+7
django dry boilerplate
source share
8 answers

Of course, you can avoid repetition. Basically, you need to pass as arguments the class of the form used and the name of the template to be processed to process the cleared data when sending the valid form and the destination for redirection after such processing; plus, you need a bit of extra code to call the form class only once, to create either a connected or unrelated form, and deal with it properly. I.e:.

 def process_any_form(request, form_class, template_file_name, process_data_callable, redirect_destination): form = form_class(request.POST if request.method == 'POST' else None) if form.is_bound and form.is_valid(): process_data_callable(form.cleaned_data) return HttpResponseRedirect(redirect_destination) return render_to_response(template_file_name, {'form': form}) 
+10
source share

You are right, it could be better, here is a better alternative (but keep reading):

 def contact(request): form = ContactForm(request.POST or None) # A form bound to the POST data if form.is_valid(): # All validation rules pass # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/thanks/') # Redirect after POST return render_to_response('contact.html', { 'form': form, }) 

This snippet comes from a conversation called Advanced Use of the Django Form from DjangoCon11.

Please note that this will treat the empty form as valid (even before submission) if all fields are optional and you do not use CSRF protection. Therefore, to eliminate this risk, it is better to use it:

  def contact(request): form = ContactForm(request.POST or None) # A form bound to the POST data if request.method == 'POST' and form.is_valid(): # All validation rules pass # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/thanks/') # Redirect after POST return render_to_response('contact.html', { 'form': form, }) 
+6
source share

A typical way of processing forms mixes two problems: presenting the form for editing and processing the results. You can break this down into two methods, which will lead to some duplication in the form of identical calls to render_to_response (). By the time you reorganize this, you may get something that is less readable than the form of one method above.

When I look at the template method, I do not see duplication. The two uses of ContactForm () are different. These two conditional expressions seem to me to be quite purely demonstrating the state transitions associated with processing the form (they are an empty form, they accept applications until they are valid, processed and redirected).

+2
source share

The generic handler Alex defeated me, but FWIW we tend to a less general version of his proposal:

 def contact(request): post_data = request.POST if request.method == 'POST' else None form = ContactForm(post_data) if request.method == 'POST': # perform normal validation checking, etc return render_to_response('contact.html', { 'form': form, }) 

If post_data is None, then the form is created as unlimited. Otherwise, forwarding processing continues as usual. This avoids duplication of the ContactForm construct, but I agree that Dave replies that the duplicate construct does not bother me as a duplicate precisely because the design parameters are different.

+1
source share

I was so tired of it that I wrote my own general ideas to handle it. In the process, I discovered that django already has an underrated general view for handling forms. They are fairly straightforward analogues of documented general views, but take forms and basically follow the same pattern that you used in your example. Ultimately, I found them too inflexible and stupid for my use (I do not want the create_or_update view, I will not consider these two actions separately).

Edit: you didnโ€™t like the Fragsworth answer, which points to the same thing I'm talking about, I believe that you will not be like me either. Here is an example of how it works.

 # in urls.py urlpatterns += patterns("", (u'^...$', 'django.views.generic.create_update.update', { 'form_class': ContactForm }) ) 

ContactForm must have a save() method, and where the form processing logic goes.

+1
source share

You can write a function that processes conventions for all forms. You can do this by passing a function specific to this form after "is_valid", for example:

 def FormHandler(request, CleaningFunction, redirecturl): if request.method = 'POST': if request.method == 'POST': # If the form has been submitted... form = ContactForm(request.POST) # A form bound to the POST data if form.is_valid(): # All validation rules pass CleaningFunction(form) # Process the data in form.cleaned_data return HttpResponseRedirect('/thanks/') # Redirect after POST else: form = ContactForm() # An unbound form return form 

Then you can call FormHandler from your view. Please note that this is not verified and may have errors.

0
source share

Django provides several general views for creating, editing, and deleting objects. Perhaps you could try them.

0
source share

You can bypass the django forms module and just do it the old way, you will get more flexibility without too much IMHO loss.

The last time I looked at django forms, it was quite a while ago, I donโ€™t know if things have changed, but, for example, in fact this does not allow you to create an ajax-style form; at least not easy.

0
source share

All Articles