Django:如何基于行中的数据和其他Model中的数据向查询集添加聚合字段?

问题描述 投票:0回答:1

我有一个具有以下模型的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_amountmax_amount字段将始终以美元表示值。

我需要能够基于min_amountmax_amount过滤查询集,但为此,所有金额必须以美元为单位。要将捐赠金额转换为美元,我需要乘以捐赠货币和日期的汇率。

到目前为止,我发现这样做的唯一方法是迭代dict(queryset)并添加一个名为usd_amount的新值,但是将来可能会提供非常差的性能。

阅读Django文档,似乎可以使用聚合来完成相同的事情,但是到目前为止,我还无法创建正确的逻辑以产生相同的结果。

python django django-queryset aggregation
1个回答
0
投票

我知道我必须使用注释来解决此问题,但我不知道具体如何做,因为它涉及从不相关的模型中获取数据。

经进一步调查,我在Django文档中找到了所需的内容。我需要使用SubqueryOuterRef表达式从外部查询集中获取值,以便可以过滤内部查询集。

最终解决方案如下:

# 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)
© www.soinside.com 2019 - 2024. All rights reserved.