如何通过单次Django ORM查询获取多值及指定团队双月计数?
嘿,我来帮你搞定这两个Django ORM的问题,结合你给出的Test模型和数据,直接上实用的解决方案:
问题1:如何从单次Django ORM查询中获取多个值?
Django ORM提供了多种方式在单次查询里批量获取多组值,最常用的是结合values()/values_list()与聚合函数,或者用annotate()做分组聚合,下面举几个贴合你数据场景的例子:
场景1:按分组获取多维度聚合值
比如想获取每个team对应的记录总数、所有id列表,以及最早/最晚的创建时间,一次查询就能搞定:
from django.db.models import Count, ArrayAgg, Min, Max result = Test.objects.values('team').annotate( record_count=Count('id'), all_ids=ArrayAgg('id'), earliest_created=Min('created_at'), latest_created=Max('created_at') ).order_by('team') # 返回结果示例: # [ # {'team':1, 'record_count':3, 'all_ids':[1,2,3], 'earliest_created': datetime(2018,2,14,...), 'latest_created': datetime(2018,3,14,...)}, # {'team':3, 'record_count':6, 'all_ids':[4,5,6,7,8,9], 'earliest_created': datetime(2018,3,12,...), 'latest_created': datetime(2018,5,11,...)} # ]
场景2:获取单个对象的多个指定字段值
如果只需要某条记录的特定字段,用values()配合first()就能拿到字典格式的多值结果:
single_obj_data = Test.objects.filter(id=1).values('team', 'created_at').first() # 得到:{'team':1, 'created_at': datetime(2018,2,14, 10,33,46,...)}
问题2:如何通过单次查询获取team=3的当月数据计数与上月数据计数?
这里可以用Case+When条件判断配合Count聚合,一次查询就能同时统计两个时间段的记录数,推荐两种实现方式:
方式1:基于时间范围动态计算(通用,跨年份也适用)
from django.db.models import Count, Case, When from django.utils import timezone from datetime import timedelta now = timezone.now() # 计算当月起始时间(当月第一天0点) current_month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) # 计算上月的起始与结束时间 last_month_start = (current_month_start - timedelta(days=1)).replace(day=1) last_month_end = current_month_start - timedelta(microseconds=1) # 单次查询统计两个计数 result = Test.objects.filter(team=3).aggregate( current_month_count=Count(Case(When(created_at__gte=current_month_start, then=1))), last_month_count=Count(Case(When(created_at__range=(last_month_start, last_month_end), then=1))) ) # 结合你的数据,如果当前是2018年5月,结果会是: # {'current_month_count':1, 'last_month_count':2}
方式2:提取年月做匹配(适合数据集中在同一年的场景)
from django.db.models import Count, Case, When from django.db.models.functions import ExtractMonth, ExtractYear from django.utils import timezone now = timezone.now() current_year = now.year current_month = now.month # 处理跨年的情况(比如1月的上月是去年12月) last_month = current_month - 1 if current_month > 1 else 12 last_year = current_year if current_month > 1 else current_year - 1 result = Test.objects.filter(team=3).annotate( record_year=ExtractYear('created_at'), record_month=ExtractMonth('created_at') ).aggregate( current_month_count=Count(Case(When(record_year=current_year, record_month=current_month, then=1))), last_month_count=Count(Case(When(record_year=last_year, record_month=last_month, then=1))) )
内容的提问来源于stack exchange,提问作者Bharat Bittu
相关产品推荐
相关产品推荐

