Deepan S
Deepan S

Reputation: 51

How to maintain insert ordering for one-to-many relationship in Django

How to maintain insert ordering with one-to-many Django mapping, for eg: Say we have,

class Person(models.Model):
    name = Model.CharField(max_length=50)

class Subject(models.Model):
    sub_name = Model.CharField(max_length=50)
    person = Model.ForeignKey('Person')

def insert_data():
    person = Person.objects.create(name='Deepan')
    Subject(name='Eng', person=person).save()
    Subject(name='Sci', person=person).save()

Subject.objects.filter(person=person) # is there a way to make this to always return the subjects in the inserted order, i.e Eng, Sci instead of Sci, Eng

This is handled using list types in hibernate/grails

Upvotes: 5

Views: 5285

Answers (4)

RuBiCK
RuBiCK

Reputation: 865

I was looking for exactly the same and to order_with_respecto_to works:

class Game(models.Model):
    title = models.CharField(max_length=255)

class Task(models.Model):
    title = models.CharField(max_length=255)
    game = models.ForeignKey(Game, on_delete=models.CASCADE)

    class Meta:
        order_with_respect_to = 'game'

You can see the original order as they where inserted and you can modify it if you want. Also you can get the next register in sequence

>>> from prueba.models import Game,Task
>>> a=Game.objects.get(id=1)
>>> a.get_task_order()
<QuerySet [1, 2, 3]>
>>> a.set_task_order([3,2,1])
>>> a.get_task_order()
<QuerySet [3, 2, 1]>
>>> t=Task.objects.get(id=2)
>>> t.get_next_in_order()
<Task: task1>
>>> t=Task.objects.get(id=3)
>>> t.get_next_in_order()
<Task: task2>

Here is the documentation https://docs.djangoproject.com/en/3.0/ref/models/options/#order-with-respect-to

Upvotes: 0

nide
nide

Reputation: 34

class Meta:
    ordering = ['id']

And no additional fields required. Django model always has 'id' field.

Upvotes: 1

crodjer
crodjer

Reputation: 13614

Define the ordering using meta info:

class Subject(models.Model):
    sub_name = models.CharField(max_length=50)
    person = models.ForeignKey('Person')
    time = models.DateTimeField(auto_now_add = True)

    class Meta:
        ordering = ['time'] #or ['-time'] according to the ordering you require

This will save the creation datetime in the time field and hence the results will be ordered according to addition time.

btw (if there are some other reasons) from your models it seems there will be many Persons and many Subjects so I suggest using many to many fields. This will map multiple users to multiple subjects and symmetrically back. You may even use the through option to store more details (time etc for sorting, even marks/percentage for storing records if you require to do that) per Person-Subject mapping.

Upvotes: 4

the_drow
the_drow

Reputation: 19181

You need to use a meta class to always sort it and use a date time field with the auto_now option set to True.
I recommend using a proxy class for the sorting. Sorting is an expensive operation.
See this link for more details on sorting and this link on proxy models.

Upvotes: 2

Related Questions