Django多对多(含中间表):单查询获取用户权限卡片及所有权状态
Django单查询获取用户可访问卡片及所有权状态
现有Django模型
from django.db import models class Person(models.Model): name = models.CharField(max_length=100) # 其他业务字段 class Card(models.Model): title = models.CharField(max_length=100) # 其他业务字段 class Permissions(models.Model): person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='card_permissions') card = models.ForeignKey(Card, on_delete=models.CASCADE, related_name='user_permissions') is_owner = models.BooleanField(default=False) # 其他权限控制字段
单查询实现方案
通过annotate结合Case/When表达式,关联Permissions表完成单次查询,同时获取卡片信息与所有权状态:
from django.db.models import Case, When, BooleanField, Value # 替换为目标用户的ID target_person_id = 1 # 执行查询 accessible_cards = Card.objects.filter( user_permissions__person_id=target_person_id ).annotate( is_owner=Case( When(user_permissions__person_id=target_person_id, user_permissions__is_owner=True, then=Value(True)), default=Value(False), output_field=BooleanField() ) ).distinct()
代码说明
filter:筛选出当前用户有权访问的所有卡片annotate:通过条件判断为每张卡片添加is_owner字段,标记是否为当前用户所有distinct:避免因Permissions表关联产生的重复卡片记录
查询结果示例
返回的QuerySet中每个Card实例会携带额外的is_owner属性,示例数据如下:
<Card: 会员卡A>, is_owner=True <Card: 优惠券B>, is_owner=False <Card: 储值卡C>, is_owner=True
对应理想SQL逻辑
该Django查询生成的SQL与你期望的逻辑完全匹配,大致SQL语句如下:
SELECT DISTINCT "card".*, CASE WHEN "permissions"."is_owner" THEN TRUE ELSE FALSE END AS "is_owner" FROM "card" INNER JOIN "permissions" ON ("card"."id" = "permissions"."card_id") WHERE "permissions"."person_id" = 1;
内容的提问来源于stack exchange,提问作者Nuubles
相关产品推荐
相关产品推荐

