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. Template tag - list punctuation for a list of items by shapiromatron 10 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 5 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

Please login first before commenting.