Django:进行复杂注释和聚合的问题
Django: Problem in doing complex annotation and aggregation
这是型号:
class Purchase(models.Model):
date = models.DateField(default=datetime.date.today,blank=False, null=True)
total_purchase = models.DecimalField(max_digits=10,decimal_places=2,blank=True, null=True)
我想在特定日期范围内按月计算 "total_purchase",如果一个月内没有购买,则总购买量应为上个月的购买价值
如果两个月内有购买,则总购买将增加这两个...
示例:
假设用户给出的日期范围是从四月到十一月。
如果 4 月购买了 2800 美元,8 月购买了 5000 美元,10 月购买了 6000 美元。
那么输出将是这样的:
April 2800
May 2800
June 2800
July 2800
August 7800 #(2800 + 5000)
September 7800
October 13800 #(7800 + 6000)
November 13800
知道如何在 Django 查询中执行此操作吗?
谢谢
根据Mr.Raydel米兰达的回答。我做了以下
import calendar
import collections
import dateutil
start_date = datetime.date(2018, 4, 1)
end_date = datetime.date(2019, 3, 31)
results = collections.OrderedDict()
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(real_total = Case(When(Total_Purchase__isnull=True, then=0),default=F('tal_Purchase')))
date_cursor = start_date
while date_cursor < end_date:
month_partial_total = result.filter(date__month=date_cursor.month).agggate(partial_total=Sum('real_total'))['partial_total']
results[date_cursor.month] = month_partial_total
if month_partial_total == None:
month_partial_total = int(0)
else:
month_partial_total = month_partial_total
date_cursor += dateutil.relativedelta.relativedelta(months=1)
return results
但是现在输出是这样的(来自上面的例子):
April 2800
May 0
June 0
July 0
August 5000
September 0
October 6000
November 0
有谁知道如何在月份之间添加...
我想做类似
的事情
e = month_partial_total + month_partial_total.next
我想添加每个 month_partial_total 的下一个迭代值。我想这会解决我的问题..
任何人知道如何在 django 中执行此操作吗?
谢谢
我注意到你的问题中有两点:
- 结果按月排序。
- 总购买量可以是
blank
或 null
。
基于这些我会提出这个方法:
你可以获得给定月份的总数,你只需要处理 total_pushase
为空的情况(作为旁注,拥有 [= 的实例没有任何意义15=] 其中 total_purchase
为空,至少必须为 0).
阅读 Django Conditional expressions 以了解有关 When
和 Case
的更多信息。
# Annotate the filtered objects with the correct value (null) is equivalent
# to 0 for this requirement.
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(
real_total = Case(
When(total_purchase__isnull=True, then=0),
default=F('total_purchase')
)
)
# Then if you want to know the total for a specific month, use Sum.
month_partial_total = result.filter(
date__month=selected_month
).aggregate(
partial_total=Sum('real_total')
)['partial_total']
您可以在函数中使用它来实现您想要的结果:
import calendar
import collections
import dateutil
def totals(start_date, end_date):
"""
start_date and end_date are datetime.date objects.
"""
results = collections.OrderedDict() # Remember order things are added.
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(
real_total = Case(
When(total_purchase__isnull=True, then=0),
default=F('total_purchase')
)
)
date_cursor = start_date
month_partial_total = 0
while date_cursor < end_date:
# The while statement implicitly orders results (it goes from start to end).
month_partial_total += result.filter(date__month=date_cursor.month).aggregate(
partial_total=Sum('real_total')
)['partial_total']
results[date_cursor.month] = month_partial_total
# Uncomment following line if you want result contains the month names
# instead the month's integer values.
# result[calendar.month_name[month_number]] = month_partial_total
date_cursor += dateutil.relativedelta.relativedelta(months=1)
return results
由于 Django 1.11 可能能够解决这个问题SubQueries,但我从未将它用于同一模型的子查询。
解决方案
根据Mr.Raydel Miranda的回答,我终于找到了解决问题的方法...
根据我的观点,我做了以下工作并且效果很好:
import datetime
import calendar
import collections
import dateutil
start_date = datetime.date(2018, 4, 1)
end_date = datetime.date(2019, 3, 31)
results = collections.OrderedDict()
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(real_total = Case(When(Total_Purchase__isnull=True, then=0),default=F('Total_Purchase')))
date_cursor = start_date
z = 0
while date_cursor < end_date:
month_partial_total = result.filter(date__month=date_cursor.month).aggregate(partial_total=Sum('real_total'))['partial_total']
# results[date_cursor.month] = month_partial_total
if month_partial_total == None:
month_partial_total = int(0)
e = month_partial_total
else:
e = month_partial_total
z = z + e
results[date_cursor.month] = z
date_cursor += dateutil.relativedelta.relativedelta(months=1)
return results
谢谢大家
这是型号:
class Purchase(models.Model):
date = models.DateField(default=datetime.date.today,blank=False, null=True)
total_purchase = models.DecimalField(max_digits=10,decimal_places=2,blank=True, null=True)
我想在特定日期范围内按月计算 "total_purchase",如果一个月内没有购买,则总购买量应为上个月的购买价值 如果两个月内有购买,则总购买将增加这两个...
示例:
假设用户给出的日期范围是从四月到十一月。
如果 4 月购买了 2800 美元,8 月购买了 5000 美元,10 月购买了 6000 美元。
那么输出将是这样的:
April 2800
May 2800
June 2800
July 2800
August 7800 #(2800 + 5000)
September 7800
October 13800 #(7800 + 6000)
November 13800
知道如何在 Django 查询中执行此操作吗?
谢谢
根据Mr.Raydel米兰达的回答。我做了以下
import calendar
import collections
import dateutil
start_date = datetime.date(2018, 4, 1)
end_date = datetime.date(2019, 3, 31)
results = collections.OrderedDict()
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(real_total = Case(When(Total_Purchase__isnull=True, then=0),default=F('tal_Purchase')))
date_cursor = start_date
while date_cursor < end_date:
month_partial_total = result.filter(date__month=date_cursor.month).agggate(partial_total=Sum('real_total'))['partial_total']
results[date_cursor.month] = month_partial_total
if month_partial_total == None:
month_partial_total = int(0)
else:
month_partial_total = month_partial_total
date_cursor += dateutil.relativedelta.relativedelta(months=1)
return results
但是现在输出是这样的(来自上面的例子):
April 2800
May 0
June 0
July 0
August 5000
September 0
October 6000
November 0
有谁知道如何在月份之间添加... 我想做类似
的事情e = month_partial_total + month_partial_total.next
我想添加每个 month_partial_total 的下一个迭代值。我想这会解决我的问题..
任何人知道如何在 django 中执行此操作吗?
谢谢
我注意到你的问题中有两点:
- 结果按月排序。
- 总购买量可以是
blank
或null
。
基于这些我会提出这个方法:
你可以获得给定月份的总数,你只需要处理 total_pushase
为空的情况(作为旁注,拥有 [= 的实例没有任何意义15=] 其中 total_purchase
为空,至少必须为 0).
阅读 Django Conditional expressions 以了解有关 When
和 Case
的更多信息。
# Annotate the filtered objects with the correct value (null) is equivalent
# to 0 for this requirement.
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(
real_total = Case(
When(total_purchase__isnull=True, then=0),
default=F('total_purchase')
)
)
# Then if you want to know the total for a specific month, use Sum.
month_partial_total = result.filter(
date__month=selected_month
).aggregate(
partial_total=Sum('real_total')
)['partial_total']
您可以在函数中使用它来实现您想要的结果:
import calendar
import collections
import dateutil
def totals(start_date, end_date):
"""
start_date and end_date are datetime.date objects.
"""
results = collections.OrderedDict() # Remember order things are added.
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(
real_total = Case(
When(total_purchase__isnull=True, then=0),
default=F('total_purchase')
)
)
date_cursor = start_date
month_partial_total = 0
while date_cursor < end_date:
# The while statement implicitly orders results (it goes from start to end).
month_partial_total += result.filter(date__month=date_cursor.month).aggregate(
partial_total=Sum('real_total')
)['partial_total']
results[date_cursor.month] = month_partial_total
# Uncomment following line if you want result contains the month names
# instead the month's integer values.
# result[calendar.month_name[month_number]] = month_partial_total
date_cursor += dateutil.relativedelta.relativedelta(months=1)
return results
由于 Django 1.11 可能能够解决这个问题SubQueries,但我从未将它用于同一模型的子查询。
解决方案
根据Mr.Raydel Miranda的回答,我终于找到了解决问题的方法...
根据我的观点,我做了以下工作并且效果很好:
import datetime
import calendar
import collections
import dateutil
start_date = datetime.date(2018, 4, 1)
end_date = datetime.date(2019, 3, 31)
results = collections.OrderedDict()
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(real_total = Case(When(Total_Purchase__isnull=True, then=0),default=F('Total_Purchase')))
date_cursor = start_date
z = 0
while date_cursor < end_date:
month_partial_total = result.filter(date__month=date_cursor.month).aggregate(partial_total=Sum('real_total'))['partial_total']
# results[date_cursor.month] = month_partial_total
if month_partial_total == None:
month_partial_total = int(0)
e = month_partial_total
else:
e = month_partial_total
z = z + e
results[date_cursor.month] = z
date_cursor += dateutil.relativedelta.relativedelta(months=1)
return results
谢谢大家