I haven’t been doing much Django recently, but having finished college I’m enjoying getting back into it, and into actually committing code and fixing bugs again.
The next step was to finally bit the bullet and start the switch to Django newforms-admin branch for the main project I maintain that uses Django. I have to say I’m very impressed.
One of my models used a heavily customised admin page for editing it — so heavily customised, in fact, that I had eventually been forced to copy and modify the change_form.html template, and then copy and paste the entire admin change_stage view function and make tweaks to it. In total, I had these custom needs for one model:
- Which fields are visible should depend on the user using the form (previously solved with a neat hack that I enjoyed at the time, but am very glad to be rid of!)
- For the field that is hidden for some users (which is actually the ‘ownership’ field, a foreign key to User) it should be chosen for them (with no chance of them fixing the field themselves).
- Normal users need to be able to access the ‘Add’ form, yet preferably without normally having ‘add permission’ for that model.
- Normal users need to be able to change instances they created, but no-one else’s (so they don’t have ‘change permission’ either).
- After editing, users should be redirected back to a custom page, not the ‘change list’.
- Some fields are ‘required fields’, but the until the user has checked the ‘finished’ field, these fields are allowed to have null/blank values. (This was previously solved using a decorator like function that wrapped model fields and added ‘validators’, but validation doesn’t work that way in newforms).
- There is one custom field type, like a CharField, but with input validated to be in the form YYYY/MM.
- As the widget for NullBooleanField, a ‘Yes/No’ radio button widget should be used, but one that is nullable without obviously having a ‘null’ option. (i.e. it only shows ‘Yes’ and ‘No’ radio buttons, but you can leave it with neither selected when saving it). These fields also needed to work with the ‘required field’ functionality above.
- A timestamp field should be updated whenever the model is added or changed.
- A special notice needs to be displayed at the bottom of the change form.
Using newforms admin, I was able to implement all of these without duplicating any of admin view code or templates. I did end up with a custom template, but only to support the last requirement, and it simply inherits the normal template and fills in the after_related_objects block. The newforms method provides lots of hooks of different types — custom DB fields, custom formfields, custom widgets, custom form classes, and then the ability to override various parts of the of the view functions. In almost every case, my code mainly just delegates to super(), with some added pre- and post- logic.
Implementing all of this took some time (about a day), but partly that was due to not being very familiar with newforms, and the documentation for newforms admin isn’t yet what it could be (I added some). I often found myself getting confused between model fields and form fields — holding on to the difference between these, and then how they relate to forms and widgets, is really important to get your head around these kind of customisations.
Anyway, congrats to Brian, Joseph, Karen and everyone else who’s worked on this for the really great changes in this branch, this is excellent stuff, and very exciting.