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

如何在Django后台实现仅允许参会者查看自身参与的活动?

解决Django后台多对多模型的权限控制问题

错误原因分析

你遇到的ValueError是因为**request.user是Django内置的User模型实例**,而Event的attendees字段关联的是自定义的Person模型,两者类型不匹配,无法直接用于过滤查询。同时你的权限逻辑没有区分管理员和普通用户,导致管理员也被限制。

步骤1:关联User与Person模型

首先需要给Person模型添加与Django内置User的一对一关联,这样才能通过当前登录用户找到对应的Person实例:

# models.py
from django.contrib.auth.models import User

class Person(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='person')
    name = models.CharField(max_length=100)
    # 其他字段(id会自动生成,无需手动定义)

class Event(models.Model):
    name = models.CharField(max_length=100)
    date = models.DateTimeField()
    # 其他字段
    attendees = models.ManyToManyField(Person)

注意:需要给已有的User实例创建对应的Person记录,避免后续出现Person.DoesNotExist异常。

步骤2:修正后台权限控制逻辑

通过重写get_queryset(控制列表页显示内容)和has_view_permission(控制详情页访问权限),实现管理员可查看所有活动、普通用户仅查看自己参与的活动:

# admin.py
from django.contrib import admin
from .models import Person, Event

class EventAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        # 获取默认查询集
        qs = super().get_queryset(request)
        # 管理员直接返回全部活动
        if request.user.is_superuser:
            return qs
        # 普通用户过滤出自己参与的活动
        try:
            current_person = request.user.person
            return qs.filter(attendees=current_person)
        except Person.DoesNotExist:
            # 无对应Person记录的用户,返回空列表
            return qs.none()

    def has_view_permission(self, request, obj=None):
        # 管理员默认拥有所有权限
        if request.user.is_superuser:
            return True
        # 列表页权限已由get_queryset控制,直接返回True
        if obj is None:
            return True
        # 详情页验证当前用户是否是活动参与者
        try:
            current_person = request.user.person
            return current_person in obj.attendees.all()
        except Person.DoesNotExist:
            return False

admin.site.register(Person)
admin.site.register(Event, EventAdmin)

关键逻辑说明

  • get_queryset:负责控制后台活动列表的显示内容,管理员看到全部,普通用户只看到自己参与的活动。
  • has_view_permission:负责验证详情页的访问权限,防止用户通过直接拼接URL的方式访问不属于自己的活动详情。
  • 异常处理:针对没有对应Person记录的用户,返回空查询集或拒绝访问,避免报错。

可选优化

如果希望简化逻辑,也可以只重写get_queryset,但这样无法阻止用户通过URL直接访问活动详情(比如知道活动ID后手动输入),因此结合has_view_permission是更严谨的方案。

内容的提问来源于stack exchange,提问作者zonkidus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 20:52:20