I have three models which are related all to one model.
class MyModelParent(models.Model): name = models.CharField(max_lenght=36, blank=True) def __str__(self): return self.name or "" class MyFirstModel(models.Model): mymodelparent = models.ForeignKey(MyModelParent, related_name="first_models", blank=True, Null=True, on_delete=models.CASCADE ranking = models.IntegerField(max_lenght=36, blank=True) def __str__(self): return self.name or "" class MySecondModel(models.Model): mymodelparent = models.ForeignKey(MyModelParent, related_name="second_models", blank=True, Null=True, on_delete=models.CASCADE ranking = models.IntegerField(max_lenght=36, blank=True) def __str__(self): return self.name or "" class MyThirdModel(models.Model): mymodelparent = models.ForeignKey(MyModelParent, related_name="third_models", blank=True, Null=True, on_delete=models.CASCADE ranking = models.IntegerField(max_lenght=36, blank=True) def __str__(self): return self.ranking or ""
I am rendering MyParentModel in DetailView (CBV) and passing related models as a context to render individual models ‘ranking’ field on the same template.
Now I need to render same ‘ranking’ on MyParentModel ListView, but I only want to display ‘ranking’ which has highest value. Question is, how I can compare my related models ‘ranking integer value’ and display highest on MyParentModel ListView page?
Advertisement
Answer
You can compare different fields using Greatest and compare the values of the fields themselves using Max()
– an aggregation will return to you the single greatest value:
from django.db.models import Max from django.db.models.functions import Greatest MyModelParent.objects.aggregate( max=Greatest( Max('first_models__ranking'), Max('second_models__ranking'), Max('third_models__ranking'), ) ) # output: {'max': 230}
Edit – Explanation
There are three parts to this query:
Max – this finds the maximum value of the provided field, we are using double underscore notation to access the
ranking
field of the related model becauseranking
is not a field ofMyModelParent
.Greatest – because
Max
only works on fields, we cannot use it to find the max of the max (if that makes sense). Instead, we need to useGreatest
which is a DB function (whereas Max lives withindjango.db.models
) and returns the greatest value from said list. We therefore provide it with each of ourMax
values from the three different models.Aggregate – we just want the single highest figure and aggregate will squash the queryset into a dictionary – we can add other values to this if we want. Annotate can also be used if we want each queryset object to have access to this value.