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

Django类视图:未登录用户禁止访问未来日期的促销活动

Django DetailView 拦截请求实现权限控制

针对你的需求,最优做法是重写DetailView的get_object()方法——这是类视图中获取目标对象的核心环节,在这里做权限检查既符合Django类视图的设计逻辑,又能在最早的时机拦截不符合条件的请求,避免后续不必要的上下文处理。

步骤1:补充模型关联(必要前提)

首先需要给Promotion模型添加与用户的关联字段,这样才能判断登录用户是否是促销活动的所有者:

from django.contrib.auth.models import User
from django.db import models

class Promotion(models.Model):
    title = models.CharField(max_length=100, blank=False, null=False)
    # 添加用户外键,关联促销活动的创建者/所有者
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='promotions')
    promotion_date = models.DateField(blank=False, null=True)
    # 其他字段...

步骤2:重写DetailView的get_object()方法

在PromotionDetailView中重写get_object(),获取对象后直接进行权限判断:

from django.views import generic
from django.shortcuts import redirect
from django.utils import timezone
from django.core.exceptions import PermissionDenied
from .models import Promotion

class PromotionDetailView(generic.DetailView):
    model = Promotion
    context_object_name = 'promotion'  # 建议修正命名,和模型对应更清晰
    template_name = 'PromoManager/book_detail.html'

    def get_object(self, queryset=None):
        # 调用父类方法获取目标促销对象
        obj = super().get_object(queryset=queryset)
        today = timezone.now().date()

        # 判断促销是否为未来活动
        if obj.promotion_date and obj.promotion_date > today:
            # 未登录用户:直接重定向到登录页(或指定页面)
            if not self.request.user.is_authenticated:
                return redirect('login')  # 替换为你的登录页URL名称
            # 已登录用户:仅允许查看自己的促销活动
            if obj.user != self.request.user:
                # 可选:抛出403无权限异常,或重定向到无权限提示页
                raise PermissionDenied
                # 或者用重定向:return redirect('no_permission_page')
        # 权限符合要求,返回对象
        return obj

为什么选择get_object()而不是get_context_data?

  • get_context_data()是对象获取完成后组装模板上下文的方法,此时拦截请求已经晚了一步——对象已被查询出来,不符合权限的请求已触发数据库查询,效率更低。
  • get_object()是类视图获取目标对象的入口,在这里做权限检查能直接终止后续流程,是最直接高效的方式。

备选方案:重写dispatch()方法

如果希望在请求分发的最早期就进行检查,也可以重写dispatch()方法(所有类视图处理请求的入口):

def dispatch(self, request, *args, **kwargs):
    # 先获取对象
    obj = self.get_object()
    today = timezone.now().date()
    
    if obj.promotion_date and obj.promotion_date > today:
        if not request.user.is_authenticated:
            return redirect('login')
        if obj.user != request.user:
            raise PermissionDenied
    
    return super().dispatch(request, *args, **kwargs)

这种方式和get_object()效果类似,但get_object()更聚焦于对象级别的权限控制,代码逻辑更贴合DetailView的职责。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:35:22