我正在Django中为MySQL数据库运行一个复杂的查询,结果与预期不同。
我使用Django函数TruncMonth((每月对结果进行注释,这与预期的一样有效。一旦查询集按月份进行了注释,我最终添加了每月有多少订单的计数,这再次按预期工作。
然而,当我试图获得当月的收入时,它会以某种方式影响每月总订单的计数(见下文(。
models.py
class Order(models.Model):
OrderId = models.BigAutoField(primary_key= True)
OrderDate = models.DateTimeField(default= timezone.now, verbose_name= 'Order Date')
...
class OrderItem(models.Model):
OrderItemId = models.BigAutoField(primary_key= True)
ArtworkItemId = models.ForeignKey(ArtworkItem, on_delete= models.SET_NULL, null= True, verbose_name= 'Artwork Item')
OrderId = models.ForeignKey(Order, on_delete= models.CASCADE, verbose_name= 'Order')
ItemQuantity = models.IntegerField(verbose_name= 'Quantity')
完整查询:
Order.objects.annotate(year= ExtractYear('OrderDate'),
month= TruncMonth('OrderDate')).values(
'year', 'month').filter(
year= timezone.now().year, OrderPaid= True).annotate(
orders= Count('OrderId'), revenue= Sum(F('orderitem__ArtworkItemId__ArtworkPrice') * F('orderitem__ItemQuantity')))
# <QuerySet [{'year': 2022, 'month': 'Jul', 'orders': 1, 'revenue': Decimal('180')}, {'year': 2022, 'month': 'Aug', 'orders': 3, 'revenue': Decimal('525')}]>
然而,当我删除revenue
参数(具有相反关系(时:
Order.objects.annotate(year= ExtractYear('OrderDate'),
month= TruncMonth('OrderDate')).values(
'year', 'month').filter(
year= timezone.now().year, OrderPaid= True).annotate(
orders= Count('OrderId'))
# <QuerySet [{'year': 2022, 'month': 'Jul', 'orders': 1}, {'year': 2022, 'month': 'Aug', 'orders': 2}]>
CCD_ 3键值对具有正确的值:7月为1,8月为2。
似乎在查找外键时,它统计的是OrderItems的数量,而不是Orders。我不知道这里发生了什么,如果能给我建议,我将不胜感激。
您可以简单地执行以下操作:
qs_order = Order.objects.filter(
OrderDate__year=timezone.now().year
OrderPaid=True
).annotate(
revenue=F('orderitem__ArtworkItemId__ArtworkPrice') * F('orderitem__ItemQuantity')
)
count = qs_order.count()
total_revenue = qs_order.aggregate(tot=Sum(F('revenue'))['tot']
我会把我的答案留在这里,以备将来有帮助。
我通过在Count
函数上设置distinct = True
解决了这个问题
我从测试中得到的解释:
在annotate()
调用中,django似乎从反向关系的角度(如果存在任何关系的话(格式化了SQL。因此,例如,在本例中,所有字段调用最终都是从反向关系orderitem
的位置进行评估的(尽管原始调用来自Order
(。
更清楚的是,循环的每个orderitem
都在访问OrderId__OrderId
属性,每次都会添加1。这不是从另一个方向来计算两个orderitems
的一个OrderId
。因此,如果每个订单有两个项目,最初会被视为两个订单。设置distinct = True
不会将重复的OrderId添加到计数中。