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 для всех процессов, которые были 'Открыты' в любой момент времени в выборке диапазона дат
Моя попытка, которая работает неэффективно, но все же работает, заключается в следующем:
- Составьте список PK, которые были начаты до более поздней_даты
- Создайте списки пк процессов, которые были отбракованы или завершены до более ранней_даты .
- Удаление пк отбракованных и завершенных процессов из первого списка
- Использование окончательного отфильтрованного списка для получения соответствующих строк 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, но я не думаю, что это имеет значение, просто включаю это на всякий случай.
Заранее большое спасибо.