Home > Net >  Django - Filter same value with multiple dates
Django - Filter same value with multiple dates

Time:01-26

I'm having trouble selecting the first occurrence of the same value with multiple dates. I have the two following models in a logistic app:

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)

I'm getting multiple statuses for a parcel. For example:

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

Inside my class, I'm retrieving parcels such as:

    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

My issue is the following: as you can see, I get multiple Delivered status with different dates. I would like to only retrieve the parcel with the date 2022-12-12 15:21. In my app, if I filter with a date form, the parcel would show on the 2022-12-12, 2022-12-15 and 2022-12-22. If I select the 2022-12-15 or 22, I don't want the parcel to be shown. Basically, I only want the parcel to show if the first Delivered occurrence date matches the date I select. Do you have any idea on how I would need to modify the filter?

CodePudding user response:

You can try like this using 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

Here I am annotating the earliest of the ParcelStatus object's date with the Parcel queryset, then filtering on it.

CodePudding user response:

You could try this:

parcels = parcels.filter(parcelstatus__status='Delivered', 
parcelstatus__date__date=self.date).earliest('date')

According to the documentation it should get the earliest object with the date given by you.
Doc: https://docs.djangoproject.com/en/4.2/ref/models/querysets/#earliest

  • Related