Django - Фильтр одного и того же значения с несколькими датами
У меня проблемы с выбором первого появления одного и того же значения с несколькими датами. У меня есть две следующие модели в логистическом приложении:
class Parcel(models.Model):
""" Class designed to create parcels. """
name = models.CharField(max_length=255, blank=True, null=True)
tracking_number = models.CharField(max_length=255, blank=True, null=True)
description = models.TextField(blank=True, null=True)
class ParcelStatus(models.Model):
""" Class designed to create parcel status. """
SLA_choices = (
(_('Parcel shipped'), 'Parcel shipped'),
(_('Delivered'), 'Delivered'),
(_('In transit'), 'In transit'),
(_('Exception A'), 'Exception A'),
(_('Exception B'), 'Exception B'),
(_('Exception C'), 'Exception C'),
(_('Other'), 'Other'),
(_('Claim'), 'Claim'),
)
parcel = models.ForeignKey(Parcel, on_delete=models.CASCADE, blank=False, null=True)
status = models.CharField(max_length=255, blank=True, null=True, choices=SLA_choices)
event = models.ForeignKey(GridEventTransporter, on_delete=DO_NOTHING, blank=True, null=True)
reason = models.ForeignKey(GridReasonTransporter, on_delete=DO_NOTHING, blank=True, null=True)
date = models.DateTimeField(blank=True, null=True)
Я получаю несколько статусов для одной посылки. Например:
Parcel | Status | Date |
---|---|---|
XXXX | Delivered | 2022-22-12 13:00 |
XXXX | Delivered | 2022-15-12 18:20 |
XXXX | Delivered | 2022-12-12 15:27 |
XXXX | Delivered | 2022-12-12 15:21 |
XXXX | In transit | 2022-12-12 03:21 |
Внутри моего класса я извлекаю такие посылки, как:
def get_parcels(self):
return Parcel.objects.filter(company=self.company)
def get_parcels_delivered(self):
parcels = self.get_parcels()
parcels = parcels.filter(parcelstatus__status='Delivered', parcelstatus__date__date=self.date)
parcels = parcels.distinct()
return parcels
Моя проблема заключается в следующем: как вы можете видеть, я получаю несколько статусов Delivered
с разными датами. Я хотел бы получить только посылку с датой 2022-12-12 15:21
. В моем приложении, если я фильтрую с помощью формы даты, посылка будет показана на 2022-12-12, 2022-12-15 и 2022-12-22. Если я выбираю 2022-12-15 или 22, я не хочу, чтобы посылка была показана. В принципе, я хочу, чтобы посылка отображалась только в том случае, если первая дата появления Delivered
совпадает с датой, которую я выбрал. У вас есть идеи, как мне нужно модифицировать фильтр?
Вы можете попробовать следующее:
parcels = parcels.filter(parcelstatus__status='Delivered',
parcelstatus__date__date=self.date).earliest('date')
Согласно документации, он должен получить самый ранний объект с указанной вами датой.
Doc: https://docs.djangoproject.com/en/4.2/ref/models/querysets/#earliest
Вы можете попробовать следующим образом, используя Subquery:
from django.db.models import OuterRef, Subquery
def get_parcels_delivered(self):
parcels = self.get_parcels()
query= ParcelStatus.objects.filter(parcel_id=OuterRef('pk'), status='Delivered').order_by('date')
parcels = parcels.filter(parcelstatus__status='Delivered').annotate(parcel_delivery_date=Subquery(query.values('date')[:1])).filter(parcel_delivery_date__date=self.date)
return parcels
Здесь я аннотирую самую раннюю дату объекта ParcelStatus набором запросов Parcel, а затем фильтрую по ней.