ModelForms and FormViews
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 Meta:
-
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.
- Django class-based generic views at Django
- “Writing Web applications can be monotonous, because we repeat certain patterns again and again. Django tries to take away some of that monotony at the model and template layers, but Web developers also experience this boredom at the view level.”
More Django
- Converting an existing Django model to Django-MPTT
- Using a SQL database to mimic a filesystem will, eventually, create bottlenecks when it comes to traversing the filesystem. One solution is modified preordered tree traversal, which saves the tree structure in an easily-used manner inside the model.
- Two search bookmarklets for Django
- Bookmarklets—JavaScript code in a bookmark—can make working with big Django databases much easier.
- Fixing Django’s feed generator without hacking Django
- It looks like it’s going to be a while before the RSS feed generator in Django is going to get fixed, so I looked into subclassing as a way of getting a working guid in my Django RSS feeds.
- Django: fix_ampersands and abbreviations
- The fix_ampersands filter will miss some cases where ampersands need to be replaced.
- Custom managers for Django ForeignKeys
- I’ve got one really annoying model for keywords. There’s one category of keywords that, by default, should not show up when used as a ForeignKey for most models. Key word: most.
- 29 more pages with the topic Django, and other related pages
More Duh
- minidom self-closes empty SCRIPT tags
- Python’s minidom will self-close empty script tags—as it should. But it turns out that Firefox 3.6 and IE 8 don’t support empty script tags.
- Django using too much memory? Turn off DEBUG=True!
- DEBUG=False can save hundreds of megabytes in Django command-line scripts, and probably in Django web processes.
- Add nodes to SimpleXMLElement
- If you want to add child nodes in PHP’s SimpleXML, the correct way to do it is to add the node first, then create it.
- No distutils? Install Xcode
- If Distutils is not available on Mac OS X Leopard, install the Xcode developer tools. Also, the upgrade process I followed for upgrading from Mailman 2.1.9 to 2.1.12.
- Django QuerySet Heisenberg gotcha
- Observing a system changes the system. That’s especially true with Django’s QuerySet API.