Django:如何根据来自行的数据和来自另一个模型的数据将聚合字段添加到查询集中?
Posted
技术标签:
【中文标题】Django:如何根据来自行的数据和来自另一个模型的数据将聚合字段添加到查询集中?【英文标题】:Django: How can I add an aggregated field to a queryset based on data from the row and data from another Model? 【发布时间】:2020-07-20 05:45:03 【问题描述】:我有一个具有以下模型的 Django 应用程序:
CURRENCY_CHOICES = (('USD', 'US Dollars'), ('EUR', 'Euro'))
class ExchangeRate(models.Model):
currency = models.CharField(max_length=3, default='USD', choices=CURRENCY_CHOICES)
rate = models.FloatField()
exchange_date = models.DateField()
class Donation(models.Model):
donation_date = models.DateField()
donor = models.CharField(max_length=250)
amount = models.FloatField()
currency = models.CharField(max_length=3, default='USD', choices=CURRENCY_CHOICES)
我还有一个表格,用于根据某些标准过滤捐款:
class DonationFilterForm(forms.Form)
min_amount = models.FloatField(required=False)
max_amount = models.FloatField(required=False)
min_amount
和 max_amount
字段将始终以美元表示值。
我需要能够根据 min_amount
和 max_amount
过滤查询集,但为此,所有金额必须以美元为单位。要将捐赠金额转换为美元,我需要乘以捐赠货币和日期的汇率。
到目前为止,我发现这样做的唯一方法是迭代 dict(queryset) 并添加一个名为 usd_amount
的新值,但这可能会在未来提供非常糟糕的性能。
阅读 Django 文档,似乎可以使用聚合来完成同样的事情,但到目前为止,我还没有能够创建正确的逻辑来给我同样的结果。
【问题讨论】:
使用 annotate 获取每笔捐赠的美元值,然后使用 filter 过滤该新的带注释字段。 @KevinLee 我知道我必须使用注释来解决这个问题,我只是不知道如何。我进行了更多调查,并在 Django 文档中找到了解决方案。感谢您的帮助 干得好!通过文档自己解决问题是一项了不起的成就! 【参考方案1】:我知道我必须使用 annotate 来解决这个问题,但我不知道具体如何,因为它涉及从不相关的模型中获取数据。
经过进一步调查,我在 Django 文档中找到了我需要的内容。我需要使用Subquery 和OuterRef 表达式从外部查询集中获取值,以便过滤内部查询集。
最终的解决方案是这样的:
# Prepare the filter with dynamic fields using OuterRef
rates = ExchangeRate.objects.filter(exchange_date=OuterRef('date'), currency='EUR')
# Get the exchange rate for every donation made in Euros
qs = Donation.objects.filter(currency='EUR').annotate(exchange_rate=Subquery(rates.values('rate')[:1]))
# Get the equivalent amount in USD
qs = qs.annotate(usd_amount=F('amount') * F('exchange_rate'))
所以,最后,我可以像这样过滤生成的查询集:
final_qs = qs.filter(usd_amount__gte=min_amount, usd_amount__lte=max_amount)
【讨论】:
以上是关于Django:如何根据来自行的数据和来自另一个模型的数据将聚合字段添加到查询集中?的主要内容,如果未能解决你的问题,请参考以下文章
Django 使用外键添加到数据库,同时仍显示来自其他模型的信息