Daniel Richter
Daniel Richter

Reputation: 353

Django custom queryset sort by two fields

I need to sort a queryset for a Django admin change list view by two different factors: order_time and status.

When sorted the resulting queryset should be ordered by decreasing order_time with all items that have (item.status == 3) at the bottom of the list. Essentially I'm trying to push all completed orders to the bottom of the list regardless of their order_time.

This is what the model looks like:

def Order(models.Model);
  order_time = models.DateTimeField(null=True)
  status = models.PositiveSmallIntegerField(choices=ORDER_STATUS, default=ORDER_RECEIVED)

I've messed around with combining querysets with itertools.chain but since I'm doing this for a django change list view I specifically need to return a queryset.

Could I utilize Managers for this? Or is their a way to execute custom SQL that preorders the qs accordingly?

Here's an example of what the order queryset should look like:

ORDER    ORDER_TIME      STATUS
  3         12/3           2
  8         12/5           2
  1         12/6           1
  7         12/2           3
  10        11/12          3 

Upvotes: 0

Views: 2317

Answers (2)

Michael Fillier
Michael Fillier

Reputation: 68

How about making a model for the choices.

def Status(models.Model):
    # You could put in an 'id' or 'code' field to match up to your current status codes properly
    value = models.CharField(max_length=20)
    importance = models.IntegerField()

Then alter your model to:

class Order(models.Model);
    order_time = models.DateTimeField(null=True)
    status = models.ForeignKey('Status')

    class Meta:
        ordering = ('status__importance', 'order_time')

Create your status models and set the importance field as required, in your example set the importance of status 1 & 2 to be equal (eg 5) and set the importance of status 3 to be "heavier" (eg 10). This will group order by the importance, then the time, so statuses with the same importance will be grouped together.

Upvotes: 4

Blair
Blair

Reputation: 15828

The meta options of a model include an ordering option, which would give something like:

class Order(models.Model);
    order_time = models.DateTimeField(null=True)
    status = models.PositiveSmallIntegerField(choices=ORDER_STATUS, default=ORDER_RECEIVED)

    class Meta:
        ordering = ('status', 'order_time')

Upvotes: 0

Related Questions