ChangeManipulators on only part of a model

Posted by Ross Poulton on Wed 23 August 2006 #geeky #django #programming

Django has some cool forms management functionality that takes the hard work out of displaying forms and managing the users input. Unfortunately, the ChangeManipulator expects that all fields in a model will be updated by the ChangeManipulator, and cries about any required/not-null fields that you don't display to the user in the form.

This is a huge issue when you want to display a form to a user that only modifies a very small part of a model. For example, you have a 'product' model with a few boolean fields, and you want the user to only alter the 'description' field with a ChangeManipulator. If you were to use the standard ChangeManipulator code (from the above URL) and only displayed the field 'description' to your user, the resulting code would either wipe the values of the boolean fields, or if they're required, complain that they don't have a value.

The fix is simple, and it's been in Django since the new-admin branch late last year. Why it isn't documented, I don't know. It's somewhat explained in Django Ticket # 420.

When you call your ChangeManipulator, there is a second parameter you can use to define which fields will and won't be edited, named 'follow'. It can be used to control multi-level relationships (see the ticket for details) but in this case we want it to ignore a few non-user-editable fields:

follow = {'paid': False, 'package': False, 'reminder_list': False, 'reminder_guests': False, 'security_basic': False}
manipulator = Account.ChangeManipulator(user, follow)

What this will do is ignore the paid, package, reminder_list, reminder_guests, and security_basic fields - and the user won't be prompted with an error message for not entering required fields.

What I'd like to see is a way to exclude all fields (without writing a loop to manually make them all 'False'), and then only include a small subset of fields. In my example, I have three separate screens to edit different sections of the same model - for technical reasons the information is on one model, but for business reasons it's spread over a few screens Using {'*': False, 'edit_this_field': True} would kick ass.