Django中如何反向使用exclude内的sub_categories__role__in查询条件?
问题描述
我定义了如下SettingMenus模型:
class SettingMenus(models.Model): cat = models.ForeignKey(Setting, on_delete=models.CASCADE, related_name="menus", null=True) index = models.SmallIntegerField(validators=[MaxValueValidator(32766)], default=0) name = models.CharField(max_length=100, null=True) path = models.CharField(max_length=200, null=True, blank=True) parent = models.ForeignKey('self', null=True, blank=True, related_name='sub_categories', on_delete=models.CASCADE) role = models.ManyToManyField(UserRole, related_name="settingMenus", blank=True) tables = models.ManyToManyField(AppModels, related_name="setting_menus", blank = True,)
视图中原有查询语句:
nv1menus = SettingMenus.objects.filter( cat__company__name=company, cat__application="common", index=0, role__in=request.user.groups.all() ).exclude(sub_categories__role__in=request.user.groups.all()).distinct()
我需要实现与exclude(sub_categories__role__in=request.user.groups.all())相反的逻辑——筛选出存在满足用户角色的子菜单的记录,而非排除这类记录。尝试过sub_categories__role__in!=request.user.groups.all()和not sub_categories__role__in=request.user.groups.all(),但都无法生效。
更新说明
UserRole、UserAccess模型分别继承自django.contrib.auth.models中的Group和Permission,具体定义如下:
class UserRole(Group, CommonModel): description = models.TextField(blank=True, null=True, verbose_name="Group Description") def __str__(self): return self.name class UserAccess(Permission, CommonModel): description = models.CharField(max_length=255, null=True, blank=True, verbose_name="Permission Description") def __str__(self): return self.name class User(AbstractUser): id = models.BigAutoField(primary_key=True) mobile_number = models.CharField(max_length=15, null=True, blank=True) bio = models.TextField(verbose_name="About Me", null=True, blank=True) groups = models.ManyToManyField( UserRole, verbose_name="User Groups", blank=True, related_name="users", related_query_name="user" ) user_permissions = models.ManyToManyField( UserAccess, verbose_name="User Permissions", blank=True, related_name="users", related_query_name="user" ) def __str__(self): return self.username
解决方案
要筛选出存在至少一个子菜单拥有用户所属角色的SettingMenus记录,直接将原exclude中的条件移到filter内即可,Django的正向关联查询sub_categories__role__in本身就表示“该记录存在子菜单,且子菜单的角色包含用户的任意一个角色”。
修改后的查询语句:
nv1menus = SettingMenus.objects.filter( cat__company__name=company, cat__application="common", index=0, role__in=request.user.groups.all(), sub_categories__role__in=request.user.groups.all() ).distinct()
补充说明
- 原
exclude是排除有符合条件子菜单的记录,将该条件移入filter后,就实现了反向筛选逻辑。 - 必须保留
.distinct():一个父菜单可能对应多个符合条件的子菜单,会导致查询结果重复,distinct()用于去重。 - 如果需要同时包含“无子女菜单”的记录,可使用
Q查询扩展:
from django.db.models import Q nv1menus = SettingMenus.objects.filter( cat__company__name=company, cat__application="common", index=0, role__in=request.user.groups.all(), Q(sub_categories__isnull=True) | Q(sub_categories__role__in=request.user.groups.all()) ).distinct()
内容的提问来源于stack exchange,提问作者parmer_110
相关产品推荐
相关产品推荐

