Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How to create ordered siblings

I want to create a model that will order its children models in the appropriate way. For instance, a Book has many Chapters, but the Chapters have to be in a specific order.

I assume that I need to put an IntegerField on the Chapter model that specifies the order of the Chapters like the following question suggests: Ordered lists in django

My main issue is that whenever I want to insert a new Chapter in between two existing chapters or reorder them in any way, I have to update (almost) every Chapter in the Book. Is there a way (perhaps in the Django Admin, which I'm using) to avoid having to manually change every index on every Chapter whenever I change the order?

I'm not a big fan of creating a "Linked List" style model, as proposed in the above-linked question, as I am under the impression that's not good practice for database creation.

What is the "right" way to model this relationship?

like image 751
Thane Brimhall Avatar asked Mar 04 '26 16:03

Thane Brimhall


2 Answers

The answer you alluded to was probably the best way to handle this efficiently. Probably requiring a raw SQL statement UPDATE Chapter SET order = order + 1 WHERE book_id = <id_for_book> AND order <= <insert_index_location>. For Django 1.1+: You could use F() to write this in a single line as the following, but it might still be O(n) queries under the hood, using transactions.

Book.objects.get(id=<id_of_book>).chapter_set.filter(order__gt=<place_to_insert>).update(order=F('order')+1)
like image 104
Furbeenator Avatar answered Mar 07 '26 09:03

Furbeenator


Use a float instead of an integer to avoid your problem of updating multiple items when you insert between two.

So if you want to insert an item between item 42 and item 43, you can give it an order value halfway between the two (42.5), and you won't have to update any other items.

Insert z between x and y... z.order = (y.order - x.order) / 2 + x.order