Django queryset - Isn’t it possible to filter on a

2019-06-03 10:31发布

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.

3条回答
闹够了就滚
2楼-- · 2019-06-03 10:57

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']
查看更多
Luminary・发光体
3楼-- · 2019-06-03 11:06

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.

查看更多
【Aperson】
4楼-- · 2019-06-03 11:18

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 floats 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:

  1. Change the type of value on MyModel to a DecimalField (i.e. value = models.DecimalField(max_digits=5, decimal_places=2, null=True))

  2. 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)

查看更多
登录 后发表回答