Django模型关联查询:按月份统计作物收获面积并过滤结果
解决方案
模型补全说明
你的Crop模型定义中缺少is_active字段,但Plotting的外键关联里用到了limit_choices_to={"is_active": True}过滤条件,建议给Crop模型添加该字段,否则这个过滤规则会失效:
class Crop(models.Model): name = models.CharField(max_length=100, unique=True) description = models.TextField(null=True, blank=True) is_active = models.BooleanField(default=True) # 添加此字段
1. 数据库查询实现
使用Django ORM的聚合函数和条件判断,按作物分组统计各月份收获面积总和,同时支持日期范围过滤:
from django.db.models import Sum, Case, When, DecimalField from datetime import date def get_crop_harvest_stats(start_date=None, end_date=None): # 初始化查询集,过滤有效作物和非空收获日期 queryset = Plotting.objects.filter( crop__is_active=True, harvesting_date__isnull=False ) # 应用日期范围过滤 if start_date: queryset = queryset.filter(harvesting_date__gte=start_date) if end_date: queryset = queryset.filter(harvesting_date__lte=end_date) # 按作物分组,统计1-5月的收获面积 crop_stats = queryset.values('crop__name').annotate( jan=Sum(Case( When(harvesting_date__month=1, then='acre'), output_field=DecimalField(), default=0 )), feb=Sum(Case( When(harvesting_date__month=2, then='acre'), output_field=DecimalField(), default=0 )), mar=Sum(Case( When(harvesting_date__month=3, then='acre'), output_field=DecimalField(), default=0 )), apr=Sum(Case( When(harvesting_date__month=4, then='acre'), output_field=DecimalField(), default=0 )), may=Sum(Case( When(harvesting_date__month=5, then='acre'), output_field=DecimalField(), default=0 )) ).filter( # 排除所有月份收获面积均为0的作物 jan__gt=0 | feb__gt=0 | mar__gt=0 | apr__gt=0 | may__gt=0 ).order_by('crop__name') return crop_stats
2. 格式化输出为指定表格
将查询结果转换成你需要的表格格式:
def print_harvest_table(stats): # 打印表头 print(f"CROP NAME | JAN | FEB | MAR | APR | MAY") # 打印分隔线增强可读性 print("----------|-----|-----|-----|-----|-----") for stat in stats: # 格式化每行内容,保证对齐 print(f"{stat['crop__name']:<10} | {stat['jan']:>3} | {stat['feb']:>3} | {stat['mar']:>3} | {stat['apr']:>3} | {stat['may']:>3}")
使用示例
# 统计2024年1-5月的收获数据 start = date(2024, 1, 1) end = date(2024, 5, 31) stats = get_crop_harvest_stats(start, end) print_harvest_table(stats)
关键逻辑说明
- 用
Case/When实现条件聚合,每个月份单独计算收获面积总和 - 通过
values('crop__name')按作物名称分组统计 - 最后的
filter规则排除了所有月份收获面积都为0的作物 - 日期范围过滤通过
harvesting_date__gte和harvesting_date__lte实现,可灵活指定统计时间段
内容的提问来源于stack exchange,提问作者Harsh Sonawane
相关产品推荐
相关产品推荐

