基于关联表的Django ORM查询:按优先级控制内容访问权限
Django ORM实现按优先级的内容权限筛选
假设模型定义
先明确基础模型结构(可根据实际业务调整字段):
from django.db import models from django.contrib.auth.models import User class Filter(models.Model): name = models.CharField(max_length=100) users = models.ManyToManyField(User, related_name="assigned_filters") class Content(models.Model): title = models.CharField(max_length=200) # 其他业务字段 class ContentFilter(models.Model): content = models.ForeignKey(Content, on_delete=models.CASCADE, related_name="content_filters") filter = models.ForeignKey(Filter, on_delete=models.CASCADE) manual_order = models.IntegerField(default=0) # 数值越大,优先级越高 is_allowed = models.BooleanField() # True=允许访问,False=阻止访问
核心思路
用Django ORM的Subquery和annotate实现高效筛选:
- 先获取用户关联的所有Filter ID集合
- 对每个Content,找到其关联的、属于用户Filter的最高优先级(
manual_order最大)的ContentFilter记录 - 根据该最高优先级记录的
is_allowed值,筛选出用户可访问的内容
具体实现代码
from django.db.models import Subquery, OuterRef, Max, BooleanField, Case, When def get_allowed_contents(user): # 1. 获取用户关联的所有Filter ID user_filter_ids = user.assigned_filters.values_list('id', flat=True) if not user_filter_ids.exists(): # 无关联Filter时返回默认权限内容(这里默认全部允许,可按需修改) return Content.objects.all() # 2. 子查询:获取每个Content对应的最高manual_order值 max_order_subquery = ContentFilter.objects.filter( content=OuterRef('pk'), filter_id__in=user_filter_ids ).values('content').annotate(max_order=Max('manual_order')).values('max_order') # 3. 子查询:获取对应最高优先级的ContentFilter的is_allowed状态 allowed_subquery = ContentFilter.objects.filter( content=OuterRef('pk'), filter_id__in=user_filter_ids, manual_order=OuterRef('max_order') ).values('is_allowed')[:1] # 4. 筛选用户可访问的内容 return Content.objects.annotate( max_manual_order=Subquery(max_order_subquery), is_access_allowed=Case( # 有匹配Filter时,取最高优先级的权限 When(max_manual_order__isnull=False, then=Subquery(allowed_subquery, output_field=BooleanField())), # 无匹配Filter时的默认权限(这里设为允许,可改为False) default=True, output_field=BooleanField() ) ).filter(is_access_allowed=True)
逻辑说明
- 全程使用Django ORM原生方法,无需手写SQL
- 通过子查询一次性获取每个Content的最高优先级权限,避免循环遍历Content的低效操作
- 处理了用户无关联Filter的边界情况,默认权限可根据业务需求调整
- 优先级规则:
manual_order数值越大的Filter权限越高,其is_allowed状态会直接覆盖低优先级的设置
内容的提问来源于stack exchange,提问作者Mojtaba
相关产品推荐
相关产品推荐

