Django+Postgres使用JSONBAgg实现多字段聚合生成字典列表
解决方法
你之前的写法问题在于直接向JSONBAgg传入多个字段时,聚合函数会将所有字段值扁平化压入数组,无法实现「每个关联B对象对应一个字典」的结构。正确做法是先将每个B对象的多个字段拼装为单个JSON对象,再对这些JSON对象执行聚合。
适用Django 3.2及以上版本
直接使用内置的JSONObject函数构造单条JSON结构:
from django.contrib.postgres.aggregates import JSONBAgg from django.contrib.postgres.functions import JSONObject queryset = A.objects.annotate( # 每个JSONObject对应1个关联的B对象,键名可自定义 b_list = JSONBAgg( JSONObject( amount = 'b__amount', c_id = 'b__c__id' # 需返回其他B字段/关联C字段,在这里添加键值对即可 ) ) ).values('name', 'b_list')
返回的b_list字段即为你需要的字典列表格式,示例返回结构:
{ "name": "A对象名称", "b_list": [ {"amount": 10, "c_id": 1}, {"amount": 20, "c_id": 2} ] }
低版本Django兼容方案
如果使用的Django版本低于3.2没有JSONObject,可以用RawSQL配合json_build_object实现同样效果:
from django.contrib.postgres.aggregates import JSONBAgg from django.db.models import RawSQL queryset = A.objects.annotate( b_list = JSONBAgg( RawSQL( "json_build_object('amount', %s, 'c_id', %s)", ('b__amount', 'b__c__id') ) ) ).values('name', 'b_list')
可选优化:空关联返回空列表
默认情况下如果A对象没有关联的B对象,JSONBAgg会返回null,如果需要统一返回空列表,可以搭配Coalesce处理:
from django.contrib.postgres.aggregates import JSONBAgg from django.contrib.postgres.functions import JSONObject from django.db.models import Value, Coalesce from django.contrib.postgres.fields import JSONField queryset = A.objects.annotate( b_list = Coalesce( JSONBAgg( JSONObject(amount='b__amount', c_id='b__c__id') ), Value([], output_field=JSONField()) ) ).values('name', 'b_list')
内容的提问来源于stack exchange,提问作者AssoDiPicche
相关产品推荐
相关产品推荐

