Django中如何禁止手动输入URL访问,仅允许表单触发对应视图?
解决任务状态切换仅允许表单提交的问题
问题根源
你的done视图未限制请求方法,手动输入URL发起的GET请求也会触发状态修改;同时你尝试的装饰器逻辑完全错误——它在用户已登录时返回404,导致正常表单提交也被拦截。
方案1:直接校验请求方法与参数
from django.http import HttpResponseBadRequest, HttpResponseForbidden def done(request, pk): # 仅接受POST请求 if request.method != 'POST': return HttpResponseBadRequest("仅允许表单提交访问") # 校验必须携带is_done参数 if 'is_done' not in request.POST: return HttpResponseForbidden("非法请求") # 关键:确保任务属于当前用户,防止越权 try: task = Tasks.objects.get(pk=pk, user=request.user) except Tasks.DoesNotExist: return HttpResponseForbidden("无权操作该任务") task.is_done = request.POST.get('is_done') == 'on' task.save() # 增加默认跳转地址,避免referer为空时报错 return redirect(request.META.get('HTTP_REFERER', '/'))
方案2:使用Django表单类(更规范)
定义表单
# forms.py from django import forms class TaskDoneForm(forms.Form): is_done = forms.BooleanField(required=False)
视图实现
from django.http import HttpResponseBadRequest, HttpResponseForbidden from django.views.decorators.http import require_POST from .forms import TaskDoneForm @require_POST def done(request, pk): form = TaskDoneForm(request.POST) if not form.is_valid(): return HttpResponseForbidden("请求参数非法") try: task = Tasks.objects.get(pk=pk, user=request.user) except Tasks.DoesNotExist: return HttpResponseForbidden("无权操作该任务") task.is_done = form.cleaned_data['is_done'] task.save() return redirect(request.META.get('HTTP_REFERER', '/'))
方案3:用自带装饰器限制请求方法
Django内置require_POST装饰器可直接限制视图仅接受POST请求:
from django.views.decorators.http import require_POST from django.http import HttpResponseForbidden @require_POST def done(request, pk): if 'is_done' not in request.POST: return HttpResponseForbidden("非法请求") try: task = Tasks.objects.get(pk=pk, user=request.user) except Tasks.DoesNotExist: return HttpResponseForbidden("无权操作该任务") task.is_done = request.POST.get('is_done') == 'on' task.save() return redirect(request.META.get('HTTP_REFERER', '/'))
重要提示
- 必须添加任务归属校验(
user=request.user),避免恶意用户构造URL修改他人任务 - 为
redirect设置默认地址,防止HTTP_REFERER为空时抛出异常
内容的提问来源于stack exchange,提问作者Daniil Filippov
相关产品推荐
相关产品推荐

