You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于关联表的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实现高效筛选:

  1. 先获取用户关联的所有Filter ID集合
  2. 对每个Content,找到其关联的、属于用户Filter的最高优先级(manual_order最大)的ContentFilter记录
  3. 根据该最高优先级记录的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:05:21