Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, PHP, and whatever else I happen to feel like hacking at.

ModelForms and FormViews

Jerry Stratton, May 23, 2012

I just spent far too much time trying to figure out how to use ModelForm and FormView together in Django. The basic ListView and DetailView class-based generic views are fairly well documented, but everything else just gets cryptic one-liners in the generic views page.

And, probably because FormView and ModelForm aren’t used together much, there isn’t anything in a google search about them. So mostly what I’m doing right now is providing something for Google to pick up on and save someone else a lot of time. Most likely, you don’t want to use FormView if you’re using a ModelForm, you want UpdateView, CreateView, or DeleteView. In my case, I wanted UpdateView.

[toggle code]

  • from django.views.generic import UpdateView
  • import django.forms as forms
  • from models import Switch
  • class OnOffForm(forms.ModelForm):
    • class Meta:
      • model = Switch
      • fields = ('toggle', 'message')
  • class SwitchGetItNow(UpdateView):
    • template_name = 'library/form.html'
    • form_class = OnOffForm
    • model = Switch
    • success_url = '/library/getitnow/switch/'
    • def get_object(self, queryset=None):
      • return Switch.objects.get(option='onoff')

This is for a form that allows someone to toggle a particular service on or off, and to edit the message that gets displayed when the service is off. The model is named “Switch”, and all the UpdateView needs to do is override get_object to provide the switch that toggles this service. UpdateView will handle validating the form and providing the data.

The success_url should use reverse, but I don’t know how to do that with class-based views yet.

The HTML looks like this:

[toggle code]

  • {% if switch.toggle %}
    • <p>The service is currently available to patrons. Turn it off by unchecking the box.</p>
  • {% else %}
    • <p>The service is currently unavailable to patrons. Turn it on by checking the box.</p>
  • {% endif %}
  • <form method="post" action="">
    • {% csrf_token %}
    • <table>
      • {{ form.as_table }}
    • </table>
    • <p><input type="submit" value="Submit" /></p>
  • </form>

The model instance in question is already provided by UpdateView as its model name (switch), which means it can be used inside the template; and the form is instantiated by UpdateView from the form_class.

If you’re already at the point of making forms, you probably already know how urls.py works, but here’s how I did it:

[toggle code]

  • from django.conf.urls.defaults import *
  • from library.views import SwitchGetItNow
  • urlpatterns = patterns('',
    • (r'^switch/$', SwitchGetItNow.as_view()),
  • )

It’s just “as_view()” like any other class-based view.

  1. <- Simple math pad
  2. XDomainRequest onload ->