Django ORM фильтрация с использованием дат и данных на отдельных строках один ко многим с одинаковым related_name

Эти три модели отслеживают производственные процессы посредством сочетания статусов, определяемых пользователем, и трех предопределенных статусов: "Инициализирован", "Списан" и "Завершен". Первый статус каждого процесса всегда "Инициализирован", а его конечный статус всегда либо "Списан", либо "Завершен". Все промежуточные статусы определяются пользователем и не имеют значения для данного запроса.

models.py 
#simplified for clarity

class Process(models.Model):
    name = models.CharField(max_length=50)

class Status(models.Model):
    name = models.CharField(max_length=50)

class ProcessStatusHistory(models.Model):
    timestamp = models.DateTimeField()
    prev_status = models.ForeignKey(Status,related_name="prev_status", on_delete=models.CASCADE)
    new_status = models.ForeignKey(Status,related_name="new_status", on_delete=models.CASCADE)
    process = models.ForeignKey(PatientVisit,related_name="of_process", on_delete=models.CASCADE)

Пользователь может создать отчет с выбором диапазона дат. Каков наиболее чистый способ запросить у БД следующее:

Все строки ProcessStatusHistory (даже вне диапазона дат) для процессов, которые были: не 'Инициализированы' после более поздней даты в выборке диапазона дат (случай: Процесс еще не начат для диапазона дат) И еще не были 'Списаны' ИЛИ 'Завершены' до более ранней даты в выборке диапазона дат (случай: Процесс уже завершен для диапазона дат). По сути, я хочу получить всю информацию ProcessStatusHistory для всех процессов, которые были 'Открыты' в любой момент времени в выборке диапазона дат

Моя попытка, которая работает неэффективно, но все же работает, заключается в следующем:

  1. Составьте список PK, которые были начаты до более поздней_даты
  2. Создайте списки пк процессов, которые были отбракованы или завершены до более ранней_даты
  3. .
  4. Удаление пк отбракованных и завершенных процессов из первого списка
  5. Использование окончательного отфильтрованного списка для получения соответствующих строк ProccessStatusHistory
initialized_before = Process.objects
  .filter(of_process__timestamp__lte=later_date, of_process__prev_status__name="Initialized")
  .values_list('pk', flat=True)

scrapped_before = Process.objects
  .filter(of_process__timestamp__lte=earlier_date,of_process__new_status__name="Scrapped")
  .values_list('pk', flat=True)
completed_before = Process.objects
  .filter(of_process__timestamp__lte=earlier_date,of_process__new_status__name="Complete")
  .values_list('pk', flat=True)

filtered_process_ids = initialized_before.difference(scrapped_before)
filtered_process_ids = filtered_process_ids.difference(completed_before)

filtered_status_histories = ProcessStatusHistory.objects.filter(process__pk__in=filtered_process_ids)

Вероятно, есть способ получить список только этих процессов с помощью Q(), а затем prefetch_related('of_process') в конце, но у меня возникают трудности. Мне также не удалось заставить.exclude() работать так, как я хочу. Я хотел бы иметь способ сказать: проверить последнюю ProcessStatusHistory до ранней_даты, чтобы увидеть, если имя new_status__name == 'Scrapped' OR 'Complete', и если да, не включать этот процесс.

Может быть, мне нужен сериализатор? Нужно ли по-другому настроить мои модели?

В конечном итоге, эти данные будут помещены в pd dataframe, но я не думаю, что это имеет значение, просто включаю это на всякий случай.

Заранее большое спасибо.

Вернуться на верх