Django QuerySet按表达式排序

5
可能重复:
django - ordering queryset by a calculated field

如何使用order_by像order_by('field1'*'field2')一样 例如,我有以不同货币列出价格的项目,所以要订购项目-我必须进行货币转换。

class Currency(models.Model):
    code    = models.CharField(max_length=3, primary_key=True) 
    rateToUSD   = models.DecimalField(max_digits=20,decimal_places=10)

class Item(models.Model):
    priceRT     = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    cur     = models.ForeignKey(Currency)

我希望有类似这样的东西:
Item.objects.all().order_by(F('priceRT')*F('cur__rateToUSD'))

但是不幸的是它不起作用,我也在使用annotate时失败了。我该如何执行QuerySet排序,以使两个模型字段的值乘积成为结果?

一个正确的方法是用那个表达做注释,并按照它排序。 - undefined
2个回答

4
使用 extra() 方法。具体来说,使用 select 参数指定等式,使用 order_by 参数进行排序。

1
谢谢! 在我的情况下,解决方案看起来像这样 - Item.objects.filter(q&qDates).extra(select={'usdPrice': 'SELECT airsale_item.priceRT/toUSD FROM airsale_currency WHERE airsale_currency.code = airsale_item.cur_id' }).order_by('usdPrice')不幸的是,我未能在下一个额外的结果中使用一个额外的结果。 就像I.objects.extra({'xx':....}).extra({'yy': 'xx'*2}) django(实际上是db)抛出了“xx”字段丢失的错误。 无论如何,我的问题已经解决,谢谢。 - Andrew

2

简单明了的方式:在您的Item类中添加一个名为priceUSD的额外字段,并使用重写的保存方法填充它。这意味着您不必在每个查询中运行计算 - 只需在每个更新上运行计算。因此,这是好是坏取决于您是更多地编写还是读取(考虑到您的问题,也许是读取?)

类似于这样:

class Item(models.Model):
    priceRT     = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    cur     = models.ForeignKey(Currency)
    priceUSD = models.DecimalField(max_digits=15, decimal_places=2, default=0)

    def save(self,*args,**kwargs)
        self.priceUSD = self.priceRT * self.cur.rateToUSD
        super(Model,self).save(*args,**kwargs)

在我的django项目中,每当我尝试实现聪明的计算字段而不将它们存储在数据库中时,我通常发现这会带来太多的缺点,无法使用(例如无法对其进行查询,无法按其进行排序)。因此,我通常会使用自定义保存方法将适当的字段存储在数据库中,并且它可以正常工作。但是,您可能需要更多的错误检查和其他处理。

我认为这种方法的主要优点是,您可以为计算字段添加索引,在大表上使读取查询速度更快。 - Ivan Virabyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接