如何使用Django ORM实现左连接/连表查询,附模型和原生SQL参考
问题1:原生SQL语句是否正确
如果你的业务需求是查询用户asdffdsa提交的、处理状态为已完成的广告申请对应的所有广告主发布记录+申请记录,这条SQL的语法逻辑是正确的,但是有两个需要注意的细节:
- 你模型中
Ad_company_apply.is_done定义为CharField类型,若数据库中该字段存储的是字符格式的'1',SQL语句中is_done = 1需要改成is_done = '1',否则可能出现隐式类型转换导致查询结果为空 SELECT *会返回两个表的所有字段,若两张表存在同名字段(比如两张表都有idx、is_done字段),后续取数时会出现字段覆盖的问题,建议按需指定查询字段
问题2:如何用ORM实现左连接等连表查询逻辑
你当前无法用ORM做连表查询的核心原因是没有在两个模型中定义关联关系,有两种实现方式:
方案1:新增外键关联(推荐,不影响现有表结构)
因为你模型Meta中设置了managed = False,修改模型新增外键不会触发表结构变更,只要把Ad_company_apply中的parent_idx字段修改为外键即可:
class Ad_company_apply(models.Model): idx = models.AutoField(primary_key=True) # 把原来的parent_idx = models.IntegerField()替换成下面的外键定义 parent = models.ForeignKey( Ad_company, on_delete=models.DO_NOTHING, db_column='parent_idx', # 对应数据库表的实际字段名 related_name='applies' ) # 其余字段保持不变
修改后就可以直接用ORM做各种关联查询:
- 你需要的内连接查询实现:
# 结果是符合条件的Ad_company对象,可直接通过.apply访问关联的申请记录 queryset = Ad_company.objects.filter( applies__is_done='1', applies__username='asdffdsa' ).select_related('applies')
- 左连接查询实现(保留所有Ad_company记录,即使没有对应的申请记录):
from django.db.models import Prefetch queryset = Ad_company.objects.all().prefetch_related( Prefetch('applies', queryset=Ad_company_apply.objects.filter(is_done='1', username='asdffdsa')) )
方案2:不修改现有模型的实现
如果不能修改模型定义,可以用子查询或者raw方法实现:
# 子查询方式实现需求 apply_ids = Ad_company_apply.objects.filter( is_done='1', username='asdffdsa' ).values_list('parent_idx', flat=True) queryset = Ad_company.objects.filter(idx__in=apply_ids) # 直接执行原生SQL的方式 queryset = Ad_company.objects.raw(""" SELECT ad_write_company.* FROM ad_write_company INNER JOIN ad_write_company_apply ON ad_write_company.idx = ad_write_company_apply.parent_idx where ad_write_company_apply.is_done = %s and ad_write_company_apply.username = %s """, params=['1', 'asdffdsa'])
问题3:是否有其他更优的实现方案
最优方案就是前面提到的新增外键关联的方式,优势如下:
- 完全不影响现有数据库结构,仅修改Django模型的逻辑关联定义
- 后续所有关联查询都可以直接用ORM的语法实现,不需要手写原生SQL,代码可读性和可维护性更高
- 可以利用ORM的查询优化特性(比如
select_related、prefetch_related)控制连表查询的性能,避免N+1查询问题
如果业务逻辑非常简单,后续也不会有其他关联查询的需求,直接用raw方法执行你写的原生SQL也是完全可行的,注意用params传参避免SQL注入风险即可。
内容的提问来源于stack exchange,提问作者basskiller
相关产品推荐
相关产品推荐

