Why I want read-only form fields in Django

February 22, 2011

One of the things that Django has is a forms handling system, especially for forms populated from your schema models. One of the commonly requested features for it is the ability to have read-only form fields, things that will be displayed in your form but cannot be changed. So far, the official Django answer is that this is a bad idea and you don't want to do that (see for example here).

(One reason I've read for this view is that Django people consider a form to be by definition for inputing data, not displaying it.)

Well, I disagree with this view. The advantage of well supported read-only fields is uniformity; you can treat all of your form fields exactly the same, whether or not they're read-write or read-only fields. This is especially important if you are changing which fields are read-only and which are read-write on the fly depending on things like user permissions or the state of an object (for example, you might have fields which can only be set if they are initially blank).

Having this uniformity means that you can lay out all fields using a simple '{% for field in form %}' loop (or simply rely on the default form rendering). As I've experienced myself, without this uniformity things get annoying very fast; I've been basically reduced to laying out forms specific field by specific field, with conditional logic about whether some fields are included as form fields or rendered as text from the model instance. Among other downsides, this is very brittle in the face of changes to the form and model fields, since both the view logic and the form template now know about all of them.

(This points out another annoying limitation of Django templates; it's not straightforward to loop over a subset of form or model instance fields. This means that the moment you move away from doing the same thing with all fields, you usually have to completely hand-code it in your template. Or at least there is no clear and obvious way to do this, although it's relatively simple to build generic functions that generate lists to feed to template rendering.)

All of this is multiplied if you are using a model-driven formset instead of a single-record form. With model formsets, it'd be much easier if you could give the formset a list of fields that are included and fields that are read-only. (The Django admin interface actually shows just how much easier this can make life.)

I can get by without read-only form fields. They'd just make my life easier if they existed as a well-supported, well-integrated option.

(I'm aware that you can more or less implement them today as an add on, but for me the problem is that they aren't integrated into things like straightforward model forms and model formsets. You wind up having to do things by hand and the magic starts multiplying. About the time that I am defining classes on the fly, I start to think that I'm working too hard and there should be a simpler way.)

Comments on this page:

From at 2011-02-22 08:33:40:

Makes sense to me. Good post.

From at 2011-02-22 14:40:17:

Not much magic involved. Just create a read-only widget, and insert it into your ModelForm's __init__() method. Essentially (untested, possibly pseudocode):

   class MyModelForm(ModelForm):
       def __init__(self):
           super(MyModelForm, self).__init__(); 
           self.fields['fixed_field'].widget = ReadOnlyWidget()

Bam. Done.

Written on 22 February 2011.
« How to get automatic volume management on Fedora 14 without Gnome
A quick tour of my desktop »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Tue Feb 22 00:55:03 2011
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.