Ordering related objects in Django
Django models have a meta option
This option adds an
That's all very well, but if you need to change the sequence order you may well feel at a loss. The official documentation makes no mention of this option beyond a basic explanation of its purpose , and editing your objects in the built in admin app reveals no user interface for changing the ordering either. [1]
Update Feb 2009: There's now a ticket for this functionality to be added to the docs.
I managed to uncover a Python interface by delving into Django's API internals [2]. An object with related models that order with respect to it is given two handy methods:
where
Given the above example models, you can retrieve the order of an entry's comments:
And change the ordering by passing a list of comment ids back in.
N.B. Be sure to pass in the same ids returned by
Two other handy methods exist for the Comment objects,
order_with_respect_to
that allows you to order objects within the scope of a related ForeignKey object.This option adds an
_order
column to the model's database table to keep track of this ordering.That's all very well, but if you need to change the sequence order you may well feel at a loss. The official documentation makes no mention of this option beyond a basic explanation of its purpose , and editing your objects in the built in admin app reveals no user interface for changing the ordering either. [1]
Update Feb 2009: There's now a ticket for this functionality to be added to the docs.
I managed to uncover a Python interface by delving into Django's API internals [2]. An object with related models that order with respect to it is given two handy methods:
get_RELATED_order()
set_RELATED_order()
where
RELATED
is the lowercased model name of the ordered objects
class Entry(model.Model):
# ... fields
class Comment(model.Model):
entry = model.ForeignKey(Entry, related_name='comments')
# ... more fields
class Meta:
order_with_respect_to = 'entry'
Given the above example models, you can retrieve the order of an entry's comments:
>>> entry = Entry.objects.latest()
>>> entry.get_comment_order()
[1, 2, 3, 4]
And change the ordering by passing a list of comment ids back in.
>>> entry.set_comment_order([2, 1, 4, 3])
N.B. Be sure to pass in the same ids returned by
get_comment_order
Two other handy methods exist for the Comment objects,
get_next_in_order
and get_previous_in_order
[3]
>>> comment = Comment.objects.get(pk=3)
>>> comment.get_next_in_order()
<Comment: 4>
>>> comment.get_previous_in_order()
<Comment: 2>
- A very early ticket is still open to restore this functionality to the admin app, and recent activity suggests it may well reappear soon. See also this thread on the django-developers mailing list. back
- Look particularly at the two helper functions
method_set_order
andmethod_get_order
indjango.db.models.base
. back - Theoretically at least, there's still a bug in
get_previous_in_order
but it should be fixed soon. Update: Fixed by the queryset-refactor back