Дальнейшая фильтрация результатов queryset в django

У меня есть две основные модели в django с именами Applications и Status и третья модель для отслеживания статусов приложений с именем TrackApplicationStatus. Таким образом, каждый раз, когда статус приложения меняется, в таблицу TrackApplicationStatus добавляется новая запись. Текущий статус каждого приложения - это статус самой последней записи этой таблицы.

Модели определяются как:

from django.db import models


class Application(models.Model):

    name = models.CharField(max_length=100)


class Status(models.Model):

    name = models.CharField(max_length=100, blank=False, unique=True)


class TrackApplicationStatus(models.Model):

    created_at = models.DateTimeField(auto_now_add=True)
    application = models.ForeignKey(Application, on_delete=models.CASCADE, related_name='statuses')
    status = models.ForeignKey(Status, on_delete=models.SET_NULL, related_name='applications_status', null=True)

    class Meta:
        get_latest_by = ['created_at']
        ordering = ['-created_at']

На первом этапе я получаю текущие статусы каждого приложения с помощью следующего запроса django:

current_statuses = TrackApplicationStatus.objects.order_by('application_id', '-created_at').distinct('application_id')

Созданный SQL запрос выглядит следующим образом:

SELECT 
DISTINCT ON ("api_trackapplicationstatus"."application_id")
"api_trackapplicationstatus"."id", 
"api_trackapplicationstatus"."created_at", 
"api_trackapplicationstatus"."application_id", 
"api_trackapplicationstatus"."status_id" 

FROM "api_trackapplicationstatus" 

ORDER BY 
"api_trackapplicationstatus"."application_id" ASC, "api_trackapplicationstatus"."created_at" DESC

Далее я хочу получить все заявки с определенным статусом. В терминах SQL я бы применил предложение WHERE к приведенной выше таблице результатов следующим образом:

SELECT sub.application_id

FROM
(
    SELECT DISTINCT ON ("api_trackapplicationstatus"."application_id") 
    "api_trackapplicationstatus"."created_at",
    "api_trackapplicationstatus"."application_id" as application_id,
    "api_trackapplicationstatus"."status_id" as status
    
    FROM "api_trackapplicationstatus"
    ORDER BY "api_trackapplicationstatus"."application_id" ASC,
                "api_trackapplicationstatus"."created_at" DESC
) AS sub

WHERE sub.status = 3

Как я могу добиться того же самого, используя django ORM?

Вам не нужно 3 модели. Это можно просто сделать в 1 модели.

Определите свою модель следующим образом:

class Application(model.Model):
    name = model.CharField(max_length=100)
    status = models.CharField(max_length=100, blank=False, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        get_latest_by = ['created_at']
        ordering = ['-created_at']

Теперь вы можете просто отфильтровать заявки на основе их статуса:

Applications.objects.filter(status='3').order_by('-created_at')

Я нашел не очень хороший способ:

# The desired status
status=Status.objects.get(id=3)
# The current tracking item of each application
current_statuses = TrackApplicationStatus.objects.order_by('application_id', '-created_at').distinct('application_id')
# The tracking items with the current status 3
TrackApplicationStatus.objects.filter(status=status, id__in=Subquery(current_statuses.values('id')))

Соответствующий SQL:

SELECT "api_trackapplicationstatus"."id", 
"api_trackapplicationstatus"."created_at", 
"api_trackapplicationstatus"."application_id", 
"api_trackapplicationstatus"."status_id" 

FROM "api_trackapplicationstatus" 

WHERE ( 
       "api_trackapplicationstatus"."id" 
       IN (
           SELECT DISTINCT ON (U0."application_id") U0."id" 
           FROM "api_trackapplicationstatus" U0 
           ORDER BY U0."application_id" ASC, 
           U0."created_at" DESC
       ) 
       AND "api_trackapplicationstatus"."status_id" = 3
      ) 
ORDER BY "api_trackapplicationstatus"."created_at" DESC
Вернуться на верх