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

Django DeleteView如何按来源页面配置正确的success_url

Django删除视图跳转优化:按来源页面返回对应列表页(含分页)

问题背景

现有URL配置

app_name = "posts"
urlpatterns = [
    path('global/', PostListView.as_view(), name='global-list'),
    path('personal/', PersonalPostListView.as_view(), name='personal-list'),
    path('<int:pk>/', PostDetailView.as_view(), name='detail'),
    path('<int:pk>/delete/', PostDeleteView.as_view(), name='delete'),
]

模板删除链接

三个视图的模板中均使用同一删除链接:

<a href="{% url 'posts:delete' object.id %}">Delete</a>

核心需求

  • 从global/(PostListView)删除后,返回原分页的全局列表页
  • 从personal/(PersonalPostListView)删除后,返回原分页的个人列表页
  • 从详情页(PostDetailView)删除后,默认返回全局列表页

当前实现的问题

使用HTTP_REFERER作为跳转目标时,删除后会回到删除操作页(如posts/15/delete/),无法满足预期跳转需求,且无法保留分页参数。


解决方案

方案1:传递next参数(推荐,可靠性最高)

通过在删除链接中携带目标跳转URL的next参数,明确指定删除后的跳转地址,同时保留分页参数。

步骤1:修改各模板的删除链接

  • PostListView模板:
<a href="{% url 'posts:delete' object.id %}?next={{ request.get_full_path|urlencode }}">Delete</a>
  • PersonalPostListView模板:
<a href="{% url 'posts:delete' object.id %}?next={{ request.get_full_path|urlencode }}">Delete</a>
  • PostDetailView模板:
<a href="{% url 'posts:delete' object.id %}?next={% url 'posts:global-list'|urlencode %}">Delete</a>

注:request.get_full_path会包含当前页面的完整路径(含分页等查询参数),urlencode用于处理URL中的特殊字符,避免编码错误。

步骤2:修改PostDeleteView的get_success_url方法

from django.urls import reverse

class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Post

    def get_success_url(self):
        # 获取携带的next参数
        next_url = self.request.GET.get('next')
        # 校验next参数为本站内URL,防止恶意跳转
        if next_url and next_url.startswith('/'):
            return next_url
        # 兜底:默认返回全局列表页
        return reverse('posts:global-list')

方案2:解析HTTP_REFERER(无需修改模板)

若不想改动模板,可通过解析请求的HTTP_REFERER判断来源页面,自动生成跳转地址。此方案依赖浏览器发送referer,可靠性略低。

from django.urls import resolve, reverse
from urllib.parse import urlparse

class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Post

    def get_success_url(self):
        referer = self.request.META.get('HTTP_REFERER')
        if not referer:
            return reverse('posts:global-list')
        
        # 解析referer的路径部分
        parsed_referer = urlparse(referer)
        referer_path = parsed_referer.path

        try:
            # 匹配来源页面的视图名称
            match = resolve(referer_path)
            view_name = match.view_name
            # 提取分页参数(从referer的查询参数中)
            page_param = urlparse(referer).query.split('page=')[-1] if 'page=' in referer else None

            if view_name == 'posts:global-list':
                base_url = reverse('posts:global-list')
                return f"{base_url}?page={page_param}" if page_param else base_url
            elif view_name == 'posts:personal-list':
                base_url = reverse('posts:personal-list')
                return f"{base_url}?page={page_param}" if page_param else base_url
            elif view_name == 'posts:detail':
                return reverse('posts:global-list')
        except:
            # 解析失败时返回全局列表页
            return reverse('posts:global-list')
        
        return reverse('posts:global-list')

方案对比

  • 方案1:逻辑清晰,跳转目标明确,自动保留分页参数,不受浏览器referer限制,是最优选择。
  • 方案2:无需修改模板,但依赖浏览器的referer机制,存在丢失或篡改风险,仅作为备选方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 01:15:39