views:

133

answers:

1

Short description: given a queryset myQueryset, how do I select max("myfield") without actually retrieving all rows and doing max in python?

The best I can think of is max([r["myfield"] for r in myQueryset.values("myfield")]), which isn't very good if there are millions of rows.

Long description: Say I have two models in my Django app, City and Country. City has a foreign key field to Country:

class Country(models.Model):
    name = models.CharField(max_length = 256)

class City(models.Model):
    name = models.CharField(max_length = 256)
    population = models.IntegerField()
    country = models.ForeignKey(Country, related_name = 'cities')

This means that a Country instance has .cities available. Let's say I now want to write a method for Country called highest_city_population that returns the population of the largest city. Coming from a LINQ background, my natural instinct is to try myCountry.cities.max('population') or something like that, but this isn't possible.

+6  A: 

Use Aggregation (new in Django 1.1). You use it like this:

>>> from django.db.models import Max
>>> City.objects.all().aggregate(Max('population'))
{'population__max': 28025000}

To get the highest population of a City for each Country, I think you could do something like this:

>>> from django.db.models import Max
>>> Country.objects.annotate(highest_city_population = Max('city__population'))
Dominic Rodger
D'oh! Thanks! Somehow all my attempts at finding this kept hitting `annotate`, which wasn't very suitable... (looks like the answer to the longer question is therefore `myCountry.cities.aggregate(maxpop=Max('population'))['maxpop'])`
romkyns
@romkyns - can you test out the second half of my answer? I'm a bit new to aggregation, but I think (from reading the docs) that that's how it works. Let me know if not and I'll edit my answer.
Dominic Rodger
@[Dominic Rodger] Tested my own version (see comment above) inspired by your answer - and it does exactly what I need. Your example using `annotate` is not quite what I wanted - I need this value for a single, specific country rather than for all the countries there are.
romkyns