Django中如何用字典在注解里转换ArrayAgg的城市ID为名称?
解决方案
方法一:Python层面映射(简单高效)
既然已经在Python内存中拥有cities字典,最直接的方式是先查询出包含city_ids的公司列表,再遍历每个公司完成ID到城市名的映射:
from django.db.models import Subquery, OuterRef, ArrayAgg from django.contrib.postgres.fields import ArrayField # 先查询所有公司及其对应的地址ID数组 companies = list( Company.objects.all() .annotate( city_ids=Subquery( ThroughCompanyAddress.objects.filter(company_id=OuterRef("id")) .order_by() # 避免Postgres要求排序的报错 .aggregate(arr=ArrayAgg("address_id"))["arr"], output_field=ArrayField(models.IntegerField()) ) ) ) # 遍历映射城市名称 for company in companies: # 处理city_ids为None的情况,避免报错 company.cities = [cities.get(address_id, "") for address_id in (company.city_ids or [])]
这种方法无需依赖数据库特殊函数,逻辑直观,适合大多数跨库场景。
方法二:数据库层面注解(直接在查询中生成结果)
如果需要在数据库查询阶段直接得到城市名称数组,可以利用PostgreSQL的JSONB函数实现动态映射:
步骤1:导入必要模块
import json from django.db.models import Func, Value, JSONField, Subquery, OuterRef, ArrayAgg from django.contrib.postgres.fields import ArrayField
步骤2:执行查询并完成映射
# 将Python字典转为JSON字符串,传入数据库 cities_json = json.dumps(cities) companies = ( Company.objects.all() .annotate( city_ids=Subquery( ThroughCompanyAddress.objects.filter(company_id=OuterRef("id")) .order_by() .aggregate(arr=ArrayAgg("address_id"))["arr"], output_field=ArrayField(models.IntegerField()) ) ) .annotate( cities=Func( # 传入JSON格式的城市映射表 Value(cities_json, output_field=JSONField()), # 将city_ids数组拆分为单个元素并转为文本类型 Func(Func(F('city_ids'), function='unnest'), function='text'), # 聚合回数组 function='jsonb_extract_path_text', template='array_agg(%(function)s(%(expressions)s))', output_field=ArrayField(models.CharField()) ) ) )
该方法通过PostgreSQL的jsonb_extract_path_text和array_agg函数,在数据库内部完成ID到城市名的映射并聚合为数组,适合需要直接将结果用于后续数据库操作的场景。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

