Django类视图表单提交返回上一页 模板传参404问题咨询
问题根因
现有代码存在三个核心错误:
urls.py中as_view(previous_url="previous_url")的写法只会给视图类传入固定值为"previous_url"的类属性,完全无法读取URL?后拼接的查询参数。- 查询参数属于URL的附加参数,不需要在路由
path中单独定义,你触发404的原因是请求将previous_url拼接成了路径段,最终请求地址变成/entry/5131/edit/previous_url,没有匹配到任何路由规则。 - 编辑表单为POST提交,你仅在进入编辑页的GET链接中携带了上一页参数,表单中没有存储该值,提交时参数会直接丢失。
正确实现步骤
1. 修正路由配置
删除as_view()中多余的固定参数,路由不需要单独处理查询参数,Django会自动将查询参数封装到request对象中:
path('entry/<int:pk>/edit/', EntryUpdateView.as_view(), name='entry_update'),
2. 重写类视图逻辑
废弃固定类属性传值的写法,在GET请求渲染表单时将查询参数中的上一页地址传入模板上下文,在POST提交表单时从请求体中取出上一页地址,增加安全校验避免开放重定向漏洞后完成跳转:
from django.http import HttpResponseRedirect from django.urls import reverse from django.utils.http import url_has_allowed_host_and_scheme class EntryUpdateView(LoginRequiredMixin, UpdateView): model = Entry template_name = 'entry_update.html' fields = ('source', 'target', 'glossary', 'notes') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 从GET查询参数中提取上一页地址,传给模板 context['previous_url'] = self.request.GET.get('previous_url', '') return context def form_valid(self, form): obj = form.save(commit=False) obj.updated_by = self.request.user obj.save() # 从POST表单数据中提取上一页地址 redirect_url = self.request.POST.get('previous_url', '') # 安全校验:仅允许跳转至本站域名下的地址,防止恶意跳转 if not url_has_allowed_host_and_scheme( url=redirect_url, allowed_hosts={self.request.get_host()}, require_https=self.request.is_secure() ): # 校验不通过时跳转至默认兜底页面,替换为你自己的默认路由即可 redirect_url = reverse('entry_list') return HttpResponseRedirect(redirect_url)
3. 修正编辑表单模板
在表单中新增隐藏字段存储上一页地址,确保POST提交时参数能正常传递到后端:
<form method="POST" novalidate> {% csrf_token %} <!-- 新增隐藏字段存储上一页地址 --> <input type="hidden" name="previous_url" value="{{ previous_url }}"> <div class="mb-3"> {{ form.source|as_crispy_field }} </div> <div class="mb-3"> {{ form.target|as_crispy_field }} </div> <div class="mb-3"> {{ form.glossary|as_crispy_field }} </div> <div class="mb-3"> {{ form.notes|as_crispy_field }} </div> <div class="text-center mt-3"> <button type="submit" class="btn btn-outline-primary mx-2">Update</button> </div> </form>
4. 列表页跳转链接无需修改
你原有的编辑跳转链接写法正确,只要确保最终生成的链接中previous_url是跟在?后的查询参数即可,不要把参数直接拼接到路径段中。
备用简化方案
如果不需要兼容极端的参数传递场景,可以直接从请求头中读取HTTP_REFERER字段获取来源页地址,不需要额外传参,缺点是部分浏览器、隐私插件会拦截Referer头的发送,稳定性稍差:
def form_valid(self, form): obj = form.save(commit=False) obj.updated_by = self.request.user obj.save() redirect_url = self.request.META.get('HTTP_REFERER', reverse('entry_list')) return HttpResponseRedirect(redirect_url)
内容的提问来源于stack exchange,提问作者shikamaru
相关产品推荐
相关产品推荐

