I’m trying to do a very simple operation but I get an issue.
I have a simple model :
class MyModel(models.Model):
date = models.DateTimeField(null=False)
value = models.FloatField(null=True)
interval = models.IntegerField(null=True)
My goal is to get the MyModel object with the biggest value.
#Get the value
value = MyModel.objects.filter(date__gte=’2014-05-01’, date__lte=’2014-05-31’).aggregate(Max(‘value’))[‘value__max’]
# Get the object corresponding to the max value
my_object = MyModel.objects.get(value=value)
This code raise me an error : “matching query does not exist” …
I tried to hardcode a value (that exists), I have the same error.
Am I doing something wrong ? Isn’t it possible to filter on a FloatField ?
Thanks.
It is with the way floating point numbers are represented in Python (Django's FloatField
maps to Python's float
and Django's DecimalField
maps to Python's decimal
; see here).
The difference is that float
s are not precise because of the way they are represented on your computer, the decimal
type aims to remedy some of these issues that arise through that (have a look at the docs for it, they explain that very well).
Now given your case of trying to fetch a float
via an exact match you can try 2 things:
Change the type of value
on MyModel
to a DecimalField
(i.e. value = models.DecimalField(max_digits=5, decimal_places=2, null=True)
)
If you want to keep the type as a FloatField
you can try to query a range of values, however you might end up with more than 1 result (so MyModel.objects.get()
might throw an exception, complaining that the query returned more than 1 result): MyModel.objects.filter(value__range=(1.23, 1.24))
or MyModel.objects.filter(value__gte=1.23, value__lt=1.24)
An easier way to get the object with the largest value would be to order it and take the first:
value = MyModel.objects.filter(date__gte='2014-05-01', date__lte='2014-05-31').order_by('-value')[0]
That has the advantage that it's a single query rather than 2, and doesn't incur an expensive aggregation.
date
field DateTimeField
, but the code is passing strings. Specify datetime.date
instead:
import datetime
...
value = MyModel.objects.filter(
date__gte=datetime.date(2014, 5, 1),
date__lte=datetime.date(2014, 5, 31)
).aggregate(Max('value'))['value__max']