Django: Create a new object with a single order

advertisements

I have a simplified model:

class Example(models.Model):
    name = models.CharField(max_length=255, blank=False, null=False)
    order = models.PositiveIntegerField(blank=False, null=False, unique=True)

    class Meta:
        ordering = ['order']

How I can create a new object with existing order number? If I create a new object with an order number 6 for example, then previous 6 and higher orders should have their order number increased by one (7, 8, etc.). Another question is how I can reorder existing objects? Ideally, I could do it by drag and drop in admin but it should be also possible by typing new order number directly.

I have initially thousands of objects and reasonable maximum I can think of now should be less than 100,000. Normally I add new objects programmatically from JSON file and some individual changes can be done in admin.

I already tried to implement this with django-admin-sortable but no success so far. Also, I'm not sure if it can handle the case of programmatical insertion.


Because you have a lot of records to process, I would not use a recursive method on the actual Django objects. It will take too much time. But I would override the save method, before saving the object and use an SQL command.

UPDATE Example SET order = order + 1 WHERE order >= 6.

Also remember to handle the delete situation of the object in order 6, after you delete the object.

UPDATE Example SET order = order - 1 WHERE order > 6.

Edit 1:

Django has an expression called F() docs. You can use it in you case like this:

from django.db.models import F
Example.objects.filter(order__gte=self.order).update(order=F('order')+1)

Through this Django creates an update query, which is executed. It doesn't hit the database for every object.

Edit 2: For example:

class Example(models.Model):
    name = models.CharField(max_length=255, blank=False, null=False)
    order = models.PositiveIntegerField(blank=False, null=False, unique=True)

    class Meta:
        ordering = ['order']

    def save(self, *args, **kwargs):
        from django.db.models import F
        Example.objects.filter(order__gte=self.order).update(order=F('order') + 1)
        super(Example, self).save(*args, **kwargs)