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'
.