Login

SortableModel - abstract model class for sortable records

Author:
bendavis78
Posted:
June 9, 2009
Language:
Python
Version:
1.0
Score:
3 (after 3 ratings)

If you have a model that has an "ordering" column, and you want to be able to re-position records (eg, order items by priority), this base class should make it fairly easy. To use it, you extend your model using this abstract class, then hook up the pre_save event to the pre_save event of the base class, and you're good to go. Whenever you save an item, it ensures that it has a valid "order" number. The meat of this class is the "move()" method. Just call instance.move(number) where instance is your model instance, and this class will do all the logic necessary to shift around the order numbers for you.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class SortableModel(models.Model):
    """ 
    Abstract model which makes an inherited model's records sortable
    by calling instance.move(position)
    """
    order = models.IntegerField(default=0)

    class Meta:
        abstract = True
        ordering = ['order']

    @staticmethod
    def pre_save(sender, instance, **kwargs):
        """ 
        makes sure we have a value for order. This must be connected to the
        pre_save event for the inheriting model.
        """
        if not instance.order or instance.order == 0:
            #get last order
            try:
                last = sender.objects.values('order').order_by('-order')[0]
                instance.order = last['order'] + 1 
            except IndexError:
                instance.order = 1 
     

    def move(self, to):
        to = int(to)
        orig = self.order
        if to == orig:
            return
     
        # make sure initial ordering is "clean". Not ideal, but sometimes needed
        for i, f in enumerate(ReportField.objects.all()):
            f.order = i+1 
            f.save()

        # make some room
        shift, range = to < orig and (1, (to, orig-1)) or (-1, (orig+1, to))
        ReportField.objects.filter(order__range=range).update(order=F('order')+shift)
     
        # move it
        self.order = to
        self.save()

More like this

  1. codigo alto nivel by MrRocklion 1 month ago
  2. Load template from specific app by Krzysiek555 1 month, 3 weeks ago
  3. PostgreSQL JSON subqueries by dolamroth 1 month, 3 weeks ago
  4. "Magic Link" Management Command by webology 7 months ago
  5. Closest ORM models to a latitude/longitude point by simonw 7 months ago

Comments

Please login first before commenting.