Monday, August 18, 2008

OrderField for Django Models

In a lot of the models I develop, I find I need user definable ordering. Usually I create an IntegerField in my model like so:
order = models.IntegerField()
What I really wanted was functionality that feels more like an AutoField that would set the default value as an auto-increment of the maximum value of the field +1. Further more, I needed the field to be hidden from the admin interface because ordering was to to be handled by nice, safe, up/down arrows, rather than a textfield.

Unfortunately, AutoFields are reserved for primary keys only. So instead I wrote my own OrderField. In my project folder I created a fields.py file and put this in it.
from django.db.models import fields

class OrderField(fields.IntegerField):
"""Ignores the incoming value and instead gets the maximum plus one of the field."""
def pre_save(self, model_instance, value):
# if the model is new and not an update
if model_instance.id is None:
# extra attaches a a "maximum" attribute to each record returned
records = model_instance.__class__.objects.extra(select={'maximum':'SELECT MAX("Order") FROM navigation_navigation'})
if records:
# get the maximum attribute from the first record and add 1 to it
value = records[0].maximum + 1
else:
value = 1
# otherwise the model is updating, pass the attribute value through
else:
value = getattr(model_instance, self.attname)
return value

# prevent the field from being displayed in the admin interface
def formfield(self, **kwargs):
return None

1 comment:

Antonio Melé said...

Nice field. I updated it to use Django's Max aggregation function: http://www.djangosnippets.org/snippets/1861/