22

I have a model with some fields like below

class Choclate(models.Model):
    name = models.CharField(max_length=256)
    price = models.IntegerField()

So i want to get the field name that has the lowest price value, so in order to get the lowest price value, we can do like below using Aggregations

from django.db.models import Avg, Max, Min

choclates = Choclate.objects.all()
lowest_price = choclates.aggregate(Min('price'))

So finally how to get the field name, that related to lowest price value in django ?

Shiva Krishna Bavandla
  • 25,548
  • 75
  • 193
  • 313

5 Answers5

20

You can try below code to get exact thing you want

>>> from django.db.models import Min
>>> Choclate.objects.filter().values_list('name').annotate(Min('price')).order_by('price')[0]
(u'First1', 10)
>>>

First1 is the field name having price = 10 which is lowest value.

Documentation Link

phoenix
  • 7,988
  • 6
  • 39
  • 45
Prashant Gaur
  • 9,540
  • 10
  • 49
  • 71
4

If you pass the Min as positional argument, then the field's name is price__min. Otherwise, if you pass it as keyword argument, i.e. aggregate(my_min=Min('price')), then it will be available with the same name as the argument, in this case my_min. Docs

Maciej Gol
  • 15,394
  • 4
  • 33
  • 51
4

For Min and Max you may order your values (QuerySet result) and grab the first() and last():

chocolate_list = Chocolate.objects.values_list('name', 'price')
min = chocolate_list.order_by('price').first()
max = chocolate_list.order_by('price').last()

PS: Remove the filter() if you are not assigning nothing. With values_list() you are implicitly instancing the QuerySet class

Jcc.Sanabria
  • 629
  • 1
  • 12
  • 22
3

Usage of what @Maciej Gol said:

from django.db.models import Min    

lowest_price = Chocolate.objects.values('price').aggregate(Min('price'))['price__min']
Abra Cadabra
  • 141
  • 6
0

Expanding on Jcc's answer and Luciano's comment, the solution for the exact OP's question would be the following.

Code

cheapest_choclate = Choclate.objects.values_list('name', 'price').order_by('price')[0]
lowest_price = cheapest_choclate['price']
cheapest_choclate_name = cheapest_choclate['name']

Explanation

Using Choclate.objects, you obtain all objects of class Choclate from the DB.

Using .values_list('name', 'price'), you create a QuerySet with a list of tuples where each tuple contains the 'name' and 'price' of each object - e.g. [('Sweet', 79),('Bitter', 49), ('Spicy', 69)].

Using .order_by('price'), you order the tuples in the list using the price - e.g. [('Bitter', 49), ('Spicy', 69), ('Sweet', 79)].

Using [0], you select the first tuple from the list. This tuple contains the name and price of the cheapest choclate. You could also use .first() as suggested by Jcc. However, I like the [0] approach more as it can easily be changed to something else if needed - e.g. "second cheapest" choclate could be obtained using [1].

Lastly, you can obtain the price and name of the cheapest choclate from the first tuple using cheapest_choclate['price'] and cheapest_choclate['name'].

Jakub Holan
  • 303
  • 1
  • 8