如何使用Django ORM实现同表左连接查询共享对象的其他用户权限
Django ORM 实现方案
完全可以通过Django ORM实现对应需求,不需要手写原生SQL,以下是两种常用实现方式:
方案1:Q条件拼接(小数据量场景)
逻辑简单直观,适合目标用户权限数量较少的场景:
from django.db.models import Q target_user_id = 12345 # 获取目标用户所有权限的对象标识对 user_perm_objs = Permission.objects.filter(user_id=target_user_id).values("content_type_id", "object_id") # 拼接查询条件 query_filter = Q() for perm_obj in user_perm_objs: query_filter |= Q(**perm_obj) # 查询结果,加exclude可排除目标用户自己的权限记录 result = Permission.objects.filter(query_filter) # 如需排除用户自己的权限,放开下面注释 # result = result.exclude(user_id=target_user_id)
方案2:Exists关联查询(高性能场景)
生成的SQL逻辑和你提供的原生SQL一致,查询效率更高,适合生产环境大数据量场景:
from django.db.models import Exists, OuterRef target_user_id = 12345 result = Permission.objects.filter( Exists( Permission.objects.filter( user_id=target_user_id, content_type_id=OuterRef("content_type_id"), object_id=OuterRef("object_id") ) ) ) # 同上,如需排除用户自己的权限添加exclude即可 # result = result.exclude(user_id=target_user_id)
优化建议
如果经常需要执行这类查询,可以给Permission模型添加联合索引提升查询性能:
class Permission(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') class Meta: index_together = [ ["content_type_id", "object_id", "user_id"] ]
内容的提问来源于stack exchange,提问作者David Downes
相关产品推荐
相关产品推荐

