iFunction
iFunction

Reputation: 1267

django order_by using a conditional

I need to order my site based on if a field is not null. There are two fields that refer to a deadline, the main full deadline field which is a required field, and a trials field which is optional. All entries will use deadline eventually, but some will have a trials date in there and that will be the one that needs to take priority untill that date is past when it should then default to the deadline.

To try to cover just the basics or using one or the other, without it changing when the trials date is passed, I tried the following:

class Project(models.Model):
    '''
    Main Project, serves the default Projects Portal window.
    '''
    published = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
    area = models.ForeignKey(
        Area,
        related_name="project",
        on_delete=models.PROTECT
        )
    title = models.CharField(max_length=128, unique=True)
    slug = models.SlugField(max_length=64)
    summary = models.CharField(max_length=256)
    others = models.CharField(max_length=128, blank=True)
    staff_trials = models.DateField(null=True, blank=True)
    deadline = models.DateField()
    slip = models.BooleanField(default=False)

    class Meta:
        ordering = ["-slip", "staff_trials", "deadline"]

    def __str__(self):
        return self.title

It was a bit of a stab in the dark to hope it would work, but that just puts all the staff_trials first, which is not quite what I'm after, I need the dates themselves to be in order, e.g.

project A - deadline - 12/01/2020
project B - staff_trials - 15/01/2020 deadline - 01/02/2020
project C - deadline - 20/01/2020
project D - deadline - 23/01/202

So this would be the order and when the 15th is passed Project B would appear at the bottom of this list. Is there a way to do this?

Upvotes: 0

Views: 130

Answers (1)

Ozgur Akcali
Ozgur Akcali

Reputation: 5492

I think you may not be able to define this ordering on model's Meta class, but while filtering instances, you can follow an approach like the following:

Projects.objects.annotate(
    actual_deadline=Case(
        When(staff_trials__isnull=True, then=F('deadline')),
        When(staff_trials__isnull=False, then=F('staff_trials')),
        output_field=DateTimeField(),
    )
).order_by('actual_deadline')

Here we annotate each result with a DateTimeField named "actual_deadline", getting the valie of staff_trials if defined, deadline field if not defined. Then we order the results with this field.

I haven't tested the code but should work with some tweaks if not directly.

Upvotes: 2

Related Questions