Primary image for Better Use of Newforms

Better Use of Newforms

The newforms library is a huge time-saver, but when I first started using it, I still found myself writing tedious repetitve code to get it to function how I wanted. While I could get away with it on smaller sites, I recently built a site with some big forms on it and decided to improve my process.

HTML Rendering

First off, {{ form }} or {{ form.as_p }}, rarely cut it in real world apps. We need to be able to customize our forms to improve the layout or add extra information. I started using inclusion tags to render the form fields and labels. Here is my trivial inclusion tag:

@register.inclusion_tag('_display_field.html')
def display_field(field, alt_label=''):
"""
Print HTML for a newform field.
Optionally, a label can be supplied that overrides the default label generated for the form.

Example:
{% display_field form.my_field "My New Label" %}
"""

if alt_label:
field.label = alt_label
return { 'field': field }
And the accompanying <span class="caps">HTML</span>: <code class="django+html"> {% if field.errors %} <p class="error">{{ field.errors|join:&#8221;<br />&#8221; }}</p> {% endif %} <label for="{{ field.auto_id }}" {% if field.errors <span>} class=&#8220;errors&#8221;{</span> endif %}> {{ field.label }} {% if field.field.required %}<br /> <span class="required">required</span> {% endif %} </label> {{ field }} <br /> </code> This should all be pretty straight forward. The only bit of trickery here is where <tt>newforms</tt> hides the required value for a field, <tt>field.field.required</tt>. This little bit of code changed some unmanagebly large forms into an <span class="caps">HTML</span> template that looks like this: <code class="django+html"> {% display_field form.first_name <span>} {</span> display_field form.last_name <span>} {</span> display_field form.email %} </code> Now that&#8217;s a form you can live with! <strong>update 3/25</strong>: There has been some chat on the developer mailing list about fixing some of this inside Django itself.

Form Handling

This is a simple little trick, but it will go a long way towards keeping your code clean and DRY. If you often (or always) perform the same task when processing a form, get that code out of your views. Instead, create a method to handle it inside the form itself. This keeps your views easy to read and makes it easy to edit if you ever make changes to the form itself.

Here’s a quick example of creating a new user:

class UserForm(forms.Form):
first_name = forms.CharField()
last_name = forms.CharField()
email = forms.EmailField()
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput(render_value=False))

def save(self):
new_user = User.objects.create_user(username=self.cleaned_data['username'],
email=self.cleaned_data['email'],
password=self.cleaned_data['password'])
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.is_active = False
new_user.save()
return new_user
NB: For the sake of brevity, this leaves out some important error checking. Don’t use this code in production. Now your view code is dead simple:
form = UserForm(request.POST)
if form.is_valid():
user = form.save()
Hope you found this useful. More newforms shortcuts in the coming weeks.
Peter Baumgartner

About the author

Peter Baumgartner

Peter is the founder of Lincoln Loop, having built it up from a small freelance operation in 2007 to what it is today. He is constantly learning and is well-versed in many technical disciplines including devops, …