Skip to content

Instantly share code, notes, and snippets.

@frankwiles
Created July 12, 2019 21:10
Show Gist options
  • Save frankwiles/74233a1261d41a21b8987bdd64773f82 to your computer and use it in GitHub Desktop.
Save frankwiles/74233a1261d41a21b8987bdd64773f82 to your computer and use it in GitHub Desktop.
Keeping Django Models Ordered Example
from django.db import models, transaction
from django.db.models import F, Max
class StepManager(models.Manager):
"""
Manager to encapsulate bits of business logic
"""
def move(self, obj, new_order):
""" Move an object to a new order position """
qs = self.get_queryset()
with transaction.atomic():
if obj.order > int(new_order):
qs.filter(
task=obj.task, order__lt=obj.order, order__gte=new_order
).exclude(pk=obj.pk).update(order=F("order") + 1)
else:
qs.filter(
task=obj.task, order__lte=new_order, order__gt=obj.order
).exclude(pk=obj.pk).update(order=F("order") - 1)
obj.order = new_order
obj.save()
def create(self, **kwargs):
instance = self.model(**kwargs)
with transaction.atomic():
# Get our current max order number
results = self.filter(task=instance.task).aggregate(Max("order"))
current_order = results["order__max"]
if current_order is None:
current_order = 0
value = current_order + 1
instance.order = value
instance.save()
return instance
class Task(models.Model):
name = models.CharField(max_length=100)
class Step(models.Model):
task = models.ForeignKey(Task, related_name="steps", on_delete=models.CASCADE)
name = models.CharField(max_length=100)
order = models.IntegerField(default=1)
objects = StepManager()
from tasks.models import *
t = Task.objects.create(name="Test1")
s1 = Step.objects.create(task=t, name="Testing1")
s2 = Step.objects.create(task=t, name="Testing2")
s3 = Step.objects.create(task=t, name="Testing3")
s4 = Step.objects.create(task=t, name="Testing4")
# Show the existing numbers/structure
In [9]: for s in Step.objects.all():
...: print(f"pk={s.pk} order={s.order} name={s.name}")
...:
pk=1 order=1 name=Testing1
pk=2 order=2 name=Testing2
pk=3 order=3 name=Testing3
pk=4 order=4 name=Testing4
# Move the 4th item to the 2nd position
In [10]: Step.objects.move(s4, 2)
In [11]: for s in Step.objects.all():
...: print(f"pk={s.pk} order={s.order} name={s.name}")
...:
pk=1 order=1 name=Testing1
pk=2 order=3 name=Testing2
pk=3 order=4 name=Testing3
pk=4 order=2 name=Testing4
In [12]:
@Jwrecker
Copy link

Thanks, I figured it out. Your code worked great, sorry for doubting you :). Thanks for taking time to help me out! I really appreciate it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment