基于相关字段进行注释,使用过滤器
Annotate based on related field, with filters
class IncomeStream(models.Model):
product = models.ForeignKey(Product, related_name="income_streams")
from_date = models.DateTimeField(blank=True, null=True)
to_date = models.DateTimeField(blank=True, null=True)
value = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')
class Product(models.Model):
...
class Sale(models.Model):
product = models.ForeignKey(Product, related_name="sales")
created_at = models.DateTimeField(auto_now_add=True)
...
使用上述模型,假设我想使用 .annotate
.
向某些 Sale
添加一个值
此值称为 cpa
(每次操作费用):cpa 是 IncomeStream
的值,其 from_date
和 to_date
包括销售 created_at
在他们的范围内。
此外,from_date 和 to_date 都是可以为 null 的,在这种情况下我们假设它们意味着无穷大。
例如:
<IncomeStream: from 2021-10-10 to NULL, value 10$, product TEST>
<IncomeStream: from NULL to 2021-10-09, value 5$, product TEST>
<Sale: product TEST, created_at 2019-01-01, [cpa should be 5$]>
<Sale: product TEST, created_at 2021-11-01, [cpa should be 10$]>
我的问题是:是否可以仅使用 Django ORM 和注释来编写所有这些条件?如果是,如何?
我知道 F 对象可以像这样遍历关系:
Sale.objects.annotate(cpa=F('product__income_streams__value'))
但是我究竟可以在哪里编写所有逻辑来确定它应该从哪个特定 income_stream
中选择 value
?
请假设同一产品的收入流没有重叠的日期,因此上述规格不会导致冲突。
像这样的事情应该让你开始
subquery = (
IncomeStream
.objects
.values('product') # group by product primary key i.e. product_id
.filter(product=OuterRef('product'))
.filter(from_date__gte=OuterRef('created_at'))
.filter(to_date__lte=OuterRef('created_at'))
.annotate(total_value=Sum('value'))
)
然后用子查询
Sale
.objects
.annotate(
cpa=Subquery(
subquery.values('total_value')
) # subquery should return only one row so
# so just need the total_value column
)
如果没有机会在 shell 中玩这个,我自己不是 100%。不过应该差不多了。
class IncomeStream(models.Model):
product = models.ForeignKey(Product, related_name="income_streams")
from_date = models.DateTimeField(blank=True, null=True)
to_date = models.DateTimeField(blank=True, null=True)
value = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')
class Product(models.Model):
...
class Sale(models.Model):
product = models.ForeignKey(Product, related_name="sales")
created_at = models.DateTimeField(auto_now_add=True)
...
使用上述模型,假设我想使用 .annotate
.
Sale
添加一个值
此值称为 cpa
(每次操作费用):cpa 是 IncomeStream
的值,其 from_date
和 to_date
包括销售 created_at
在他们的范围内。
此外,from_date 和 to_date 都是可以为 null 的,在这种情况下我们假设它们意味着无穷大。
例如:
<IncomeStream: from 2021-10-10 to NULL, value 10$, product TEST>
<IncomeStream: from NULL to 2021-10-09, value 5$, product TEST>
<Sale: product TEST, created_at 2019-01-01, [cpa should be 5$]>
<Sale: product TEST, created_at 2021-11-01, [cpa should be 10$]>
我的问题是:是否可以仅使用 Django ORM 和注释来编写所有这些条件?如果是,如何?
我知道 F 对象可以像这样遍历关系:
Sale.objects.annotate(cpa=F('product__income_streams__value'))
但是我究竟可以在哪里编写所有逻辑来确定它应该从哪个特定 income_stream
中选择 value
?
请假设同一产品的收入流没有重叠的日期,因此上述规格不会导致冲突。
像这样的事情应该让你开始
subquery = (
IncomeStream
.objects
.values('product') # group by product primary key i.e. product_id
.filter(product=OuterRef('product'))
.filter(from_date__gte=OuterRef('created_at'))
.filter(to_date__lte=OuterRef('created_at'))
.annotate(total_value=Sum('value'))
)
然后用子查询
Sale
.objects
.annotate(
cpa=Subquery(
subquery.values('total_value')
) # subquery should return only one row so
# so just need the total_value column
)
如果没有机会在 shell 中玩这个,我自己不是 100%。不过应该差不多了。