Login

SortableModel - abstract model class for sortable records

Author:
bendavis78
Posted:
June 9, 2009
Language:
Python
Version:
1.0
Tags:
sort order sortable orderable sorted ordered
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. PositionField by jpwatts 6 years, 7 months ago
  2. Drag and drop ordering of admin list elements using jQuery UI by johj 4 years, 8 months ago
  3. Dynamic tabular inlines with optional drag-n-drop sorting by Aneon 5 years, 9 months ago
  4. Drag and drop ordering of admin list elements for Grappelli by sjaensch 4 years, 1 month ago
  5. Orderable inlines using drag and drop with jQuery UI by simon 6 years, 5 months ago

Comments

Please login first before commenting.