如何在Django ORM中实现针对同一张表的多连接查询以实现行转列
如何在Django ORM中实现针对同一张表的多连接查询以实现行转列
嘿,我完全理解你想要实现的需求——把同一个商品对应不同价格组的价格从多行转换成同一行的不同列展示,就像你给出的SQL结果那样对吧?其实在Django ORM里有几种方式可以实现,我给你详细说说:
方法一:用annotate结合Case/When(推荐,纯ORM写法)
这种方式不需要写原生SQL,完全用Django的ORM语法来实现行转列,核心是为每个价格组单独创建一个注解,通过Case和When来匹配对应的价格组ID,提取对应的价格:
from django.db.models import Case, When, F, Value, DecimalField # 为每个价格组生成对应的价格列 goods_with_prices = Goods.objects.annotate( PriceGroups_id_1_price=Case( # 匹配价格组ID为1的记录,提取对应的price值 When(price__pricegroup_id=1, then=F('price__price')), # 如果没有该价格组的记录,默认返回0.00,也可以设为Value(None)返回NULL default=Value(0.00), output_field=DecimalField() ), PriceGroups_id_2_price=Case( When(price__pricegroup_id=2, then=F('price__price')), default=Value(0.00), output_field=DecimalField() ), PriceGroups_id_3_price=Case( When(price__pricegroup_id=3, then=F('price__price')), default=Value(0.00), output_field=DecimalField() ) ).distinct() # 去重,避免同一个商品因多个Price记录重复出现
方法二:直接复用你的原生SQL(适合复杂连接场景)
既然你已经验证过原生SQL可以正常工作,那直接用Django的raw()方法执行这段SQL也是个省心的选择,尤其当ORM语法很难完全复写复杂多表连接时:
# 执行你已经写好的原生SQL goods_with_prices = Goods.objects.raw(''' SELECT goods.id, PriceGroups_id_1.price AS PriceGroups_id_1_price, PriceGroups_id_2.price AS PriceGroups_id_2_price, PriceGroups_id_3.price AS PriceGroups_id_3_price FROM price_goods AS goods LEFT JOIN price_price AS PriceGroups_id_1 ON goods.id = PriceGroups_id_1.goods_id LEFT JOIN price_price AS PriceGroups_id_2 ON goods.id = PriceGroups_id_2.goods_id LEFT JOIN price_price AS PriceGroups_id_3 ON goods.id = PriceGroups_id_3.goods_id WHERE PriceGroups_id_1.pricegroup_id = 1 AND PriceGroups_id_2.pricegroup_id = 2 AND PriceGroups_id_3.pricegroup_id = 3 ''')
进阶:动态适配价格组(如果价格组会新增)
如果你的价格组不是固定3个,未来可能新增,那硬编码每个价格组的注解就太麻烦了。可以动态构建注解参数,自动适配所有存在的价格组:
from django.db.models import Case, When, F, Value, DecimalField # 先获取所有价格组 price_groups = PriceGroups.objects.all() # 动态生成注解字典 annotations = {} for pg in price_groups: annotations[f'PriceGroups_id_{pg.id}_price'] = Case( When(price__pricegroup_id=pg.id, then=F('price__price')), default=Value(0.00), output_field=DecimalField() ) # 应用动态生成的注解 goods_with_prices = Goods.objects.annotate(**annotations).distinct()
这样不管后续新增多少价格组,代码都能自动生成对应的价格列,不用手动修改。
备注:内容来源于stack exchange,提问作者AlexK
相关产品推荐
相关产品推荐

