October 15, 2008

Django Tip: Non-editable Fields

Yesterday I explained how to subclass a DateTimeField, adding a pre_save() method to make it suitable for use as a row creation or modification timestamp. If you do this, however, you will observe that unless you add an editable=False argument to the field instantiation call they will appear as editable fields in any ModelForms containing them. It would clearly be more desirable to have these fields non-editable by default, which can easily be arranged by extending their __init__() method and changing the default value of the editable argument.

The code below also renames the fields more suitably. You can use a similar trick to create other non-editable field types, and also to change other instantiation defaults.

class ModificationDateTimeField(models.DateTimeField):
def __init__(self, editable=False, *args, **kw):
models.DateTimeField.__init__(self, editable=editable, *args, **kw)
def pre_save(self, instance, add):
val = datetime.datetime.now()
setattr(instance, self.attname, val)
return val

class CreationDateTimeField(ModificationDateTimeField):
def __init__(self, editable=False, *args, **kw):
models.DateTimeField.__init__(self, editable=editable, *args, **kw)
def pre_save(self, instance, add):
if not add:
return getattr(instance, self.attname)
return ModificationDateTimeField.pre_save(self, instance, add)

2 comments:

KN said...

Ah, very nice. I've been trying to solve this problem right now. Thanks for the post!

Steve said...

@grzywacz: of course if you are just creating models containing the standard Field types all you need to do is add editable=False to the creator calls.

I've had problems thinking of a use case for editable=True for these fields, however, since any value input by a user would be overridden by the pre_save() method.