jim*_*kes 4 python django python-2.7 django-annotate
在为方法编写测试用例时,我发现如果使用my_queryset.first().my_annotated_value,我会得到不同的结果,而不是使用my_queryset.last().my_annotated_value虽然my_queryset.count()返回1.
以下是相关的代码段:
class ShopManager(models.Manager):
def get_best_matches(self, customer):
shops = super(ShopManager, self).get_queryset().filter(employees__matches__customer=customer).annotate(max_match_percentage=Coalesce(Max('employees__matches__match_value'), 0)).order_by('-max_match_percentage')
for shop in shops:
shop.max_match_percentage = float(shop.max_match_percentage) * 100.0
return shops
Run Code Online (Sandbox Code Playgroud)
在我运行的shell中:
shops = Shop.objects.get_best_matches(customer=Customer_A)
shops.count() # returns 1
shops.first().max_match_percentage # returns 73.9843
shops.last().max_match_percentage # returns Decimal('0.739843')
Run Code Online (Sandbox Code Playgroud)
我有不同的Django的应用程序shops,matches,employees和customers.
我搜索了几个小时,检查了django文档中first()和last()的实现.我找不到任何解释这种行为的东西.
为什么价值观不同,到底发生了什么?我做错了什么或这是一个错误?
在您的get_best_matches方法中,您在循环时评估查询集,并修改shop.max_match_percentage查询集中的每个项目.
当您调用时first(),Django返回已评估的查询集中的第一个项目.
当你打电话last(),Django的尝试返回的第一项逆转查询集.这是一个新的查询集,并导致新的数据库查找.您尚未shop.max_match_percentage为此查询集设置,因此您从数据库中获取小数.
正如您所看到的,循环查询集并在从模型管理器方法返回之前修改它可能不是一个好主意.如果克隆了查询集(例如,通过进一步克隆filter(),order_by()或者在这种情况下last()),则更改将丢失.
您应该能够在查询集内部乘以100,而不是循环遍历它:
shops = super(ShopManager, self).get_queryset().filter(employees__matches__customer=customer).annotate(max_match_percentage=Coalesce(Max('employees__matches__match_value'), 0)*100).order_by('-max_match_percentage')
Run Code Online (Sandbox Code Playgroud)
如果你真的需要返回一个float而不是一个十进制字段,你可以使用Cast.