Home > front end >  Django: Return id of maximum value where grouped by foreign key
Django: Return id of maximum value where grouped by foreign key

Time:11-11

Information

I have two models:

class BookingModel(models.Model):

    [..fields..]


class BookingComponentModel(models.Model):
    STATUS_CHOICES = ['In Progress','Completed','Not Started','Incomplete','Filled','Partially Filled','Cancelled']
    STATUS_CHOICES = [(choice,choice) for choice in STATUS_CHOICES]
    COMPONENT_CHOICES = ['Test','Soak']
    COMPONENT_CHOICES = [(choice,choice) for choice in COMPONENT_CHOICES]

    booking = models.ForeignKey(BookingModel, on_delete=models.CASCADE, null=True, blank=True)
    component_type = models.CharField(max_length=20, choices=COMPONENT_CHOICES)
    status = models.CharField(max_length=50, choices=STATUS_CHOICES, default='Not Started')
    order = models.IntegerField(unique=True)

    [..fields..]

What I want

I want to get the booking component for each booking which has the last value (maximum) in order. It will also need to have a status='In Progress' and component_type='Soak'.

For example for table:

 ---- ------------ ---------------- ------------- ------- 
| id | booking_id | component_type | status      | order |
 ---- ------------ ---------------- ------------- ------- 
| 1  | 1          | Test           | Completed   | 1     |
 ---- ------------ ---------------- ------------- ------- 
| 2  | 1          | Soak           | Completed   | 2     |
 ---- ------------ ---------------- ------------- ------- 
| 3  | 1          | Soak           | In Progress | 3     |
 ---- ------------ ---------------- ------------- ------- 
| 4  | 2          | Test           | Completed   | 1     |
 ---- ------------ ---------------- ------------- ------- 
| 5  | 2          | Soak           | In Progress | 2     |
 ---- ------------ ---------------- ------------- ------- 
| 6  | 3          | Test           | In Progress | 1     |
 ---- ------------ ---------------- ------------- ------- 

Expected outcome would be id's: 4 & 6

What I've tried

I've tried the following:

BookingComponentModel.objects.values('booking').annotate(max_order=Max('order')).order_by('-booking')

This doesn't include the filtering but returns the max_order for each booking.

I would need the id of the component which has that max_order in order to put this in a sub-query and enable me to filter other conditions (status, component_type)

Thanks

CodePudding user response:

You can make use of a Subquery expression [Django-doc] and work with:

from django.db.models import OuterRef, Subquery

BookingModel.objects.annotate(
    latest_component_id=Subquery(BookingComponentModel.objects.filter(
        booking_id=OuterRef('pk'), status='In Progress', component_type='Soak'
    ).values('pk').order_by('-order')[:1])
)

The BookingModel objects that arise from this queryset will have an extra attribute latest_component_id that will contain the primary key of the latest BookingComponentModel with as status 'In Progress', and as component_type 'Soak'.

  • Related