Search code examples
pythondjangofilterormdjango-queryset

Django Python ORM models filter case


I need to filter out queryset. My model is like below:

class TimeInfo(models.Model):
    month = models.CharField(_("Дата"), max_length=20)
    day_of_week = models.CharField(_("День недели"), max_length=15)
    order_num = models.IntegerField(_("Очередность"), null=True, blank=True)
    open_time = models.DateTimeField(_("Начало поста"))
    close_time = models.DateTimeField(_("Время разговения"))

Data:

    qs = [{
        "id": 2313,
        "month": "25 марта",
        "day_of_week": "Суббота",
        "order_num": 3,
        "open_time": "2023-03-25T19:24:00+06:00",
        "close_time": "2023-03-25T05:18:00+06:00",
        "locality": 79
    },
    {
        "id": 2314,
        "month": "26 марта",
        "day_of_week": "Воскресенье",
        "order_num": 4,
        "open_time": "2023-03-26T19:26:00+06:00",
        "close_time": "2023-03-26T05:16:00+06:00",
        "locality": 79
    },]

Let's suppose today is 25 of march if datetime.now() is greater than close_time have to return next day:

    {
        "id": 2314,
        "month": "26 марта",
        "day_of_week": "Воскресенье",
        "order_num": 4,
        "open_time": "2023-03-26T19:26:00+06:00",
        "close_time": "2023-03-26T05:16:00+06:00",
        "locality": 79
    }

return todays result if smaller than or equal to

    {
        "id": 2313,
        "month": "25 марта",
        "day_of_week": "Суббота",
        "order_num": 3,
        "open_time": "2023-03-25T19:24:00+06:00",
        "close_time": "2023-03-25T05:18:00+06:00",
        "locality": 79
    }

Solution

  • You can make use of Django's Case to perform conditional expressions

    Give this a try:

    from django.db.models import Case, When, Q, F
    from datetime import datetime
    
    now = datetime.now()
    
    qs = TimeInfo.objects.annotate(
        next_day=Case(
            When(Q(close_time__lt=now), then=F('open_time') + timedelta(days=1)),
            default=F('open_time'),
            output_field=models.DateTimeField()
        )
    ).filter(
        Q(open_time__lte=now, close_time__gte=now) | Q(next_day__lte=now),
        month='25 марта', # change this to actual month name
        day_of_week='Суббота', # change this to actual day of week name
        locality=79 # change this with actual locality id
    ).order_by('-close_time')
    
    # to get the first result
    result = qs.first()