如何在Django中在POST请求后重定向到上一页

71
我遇到了一个问题,找不到解决方案。我在导航栏中有一个按钮,该按钮在所有页面上都可用,并且负责创建一些内容。
与按钮相关联的视图:
def createadv(request):
    uw = getuw(request.user.username)
    if request.method =='POST':
    form = AdverForm(request.POST, request.FILES)
    if form.is_valid():
        form.instance.user = request.user
        form.save()
        return HttpResponseRedirect('/', {'username': request.user.username, 'uw': uw})
    args = {}
    args.update(csrf(request))
    args['username'] = request.user.username
    args['form'] = AdverForm()
    args['uw'] = uw
    return  render_to_response('createadv.html', args)

如果您现在可以看到,我总是在创建内容后重定向到主页'/',但我想返回到启动内容创建的页面。

7个回答

105
你可以向表单中添加一个next字段,并将其设置为request.path。在处理完表单后,你可以重定向到此路径的值。

template.html

<form method="POST">
    {% csrf_token %}
    {{ form }}
    <input type="hidden" name="next" value="{{ request.path }}">
    <button type="submit">Let's Go</button>
</form>

视图.py

next = request.POST.get('next', '/')
return HttpResponseRedirect(next)

如果我没记错的话,django.contrib.auth 处理登录表单的大致流程如下。

如果你需要通过一个中间页面来完成登录,你可以通过查询字符串传递“next”值:

some_page.html

<a href="{% url 'your_form_view' %}?next={{ request.path|urlencode }}">Go to my form!</a>

模板.html

<form method="POST">
    {% csrf_token %}
    {{ form }}
    <input type="hidden" name="next" value="{{ request.GET.next }}">
    <button type="submit">Let's Go</button>
</form>

1
你在 get_success_url() 中放了什么?它应该返回 URL (next),而不是响应 (HttpResponseRedirect(next))。 - Antoine Pinsard
1
谢谢,那正是我的问题(返回HttpResponseRedirect(next)而不仅仅是next)。昨晚这里已经很晚了... 现在完美解决了! - Simon
2
@Shahriar.M 当然可以,你只需要将 next={{ request.path|urlencode }} 查询参数传递到产品页面的URL即可。接着,你可以使用 href="{{ request.GET.next }}" 创建返回按钮。 - Antoine Pinsard
1
重定向基本上只是服务器向客户端发送的一条消息,告诉其“转到此URL”。我不认为让用户有能力告诉服务器“告诉我转到此URL”会造成任何伤害。最坏的情况是,他们可能会被重定向到错误的URL,如果他们自己决定篡改源代码,那就与你无关了。 - Antoine Pinsard
@AntoinePinsard 我不理解 next = request.POST.get('next', '/') 中 '/' 的用法。当我应用它时,显然会将我发送回 '/'. 我认为代码的目的是将用户发送回不同的页面?那么为什么要使用'/'呢?我只是想问一下,因为我正在尝试实现这段代码,但我不知道如何将'/'应用到我的情况中。我正在尝试重定向到一个特定的 'xx/<page_id>' 页面,该页面最初是用户从中重定向到具有提交表单的产品页面的。如果更容易,我很乐意创建一个单独的问题。 - PhilM
显示剩余5条评论

57

你可以使用HTTP_REFERER值:

return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

请注意,如果客户端禁用了发送引荐信息(例如使用私密/隐身浏览器窗口),则此方法将无法正常工作。在这种情况下,它将重定向到/


1
在使用HTTP安全(HTTPS)连接时,这是否有效? - Ebram Shehata
@EbramShehata 是的,如果原始页面和重定向页面都在安全连接上提供服务,它将起作用。 - Selcuk

12
您可以使用此功能。
return redirect(request.META.get('HTTP_REFERER'))

请确保导入此文件

from django.shortcuts import redirect

3
您可以使用简单的一行JS轻松完成此操作。
<button onclick="history.back()">Go Back</button>

这将带您回到您的历史记录列表中的上一页。 如果您没有历史记录,请访问https://www.w3schools.com/jsref/met_his_back.asp


3

我最喜欢的方法是将request.path作为GET参数传递给表单。它将在重定向时一直传递。在基于类的视图(FormView、UpdateView、DeleteView或CreateView)中,您可以直接将其用作success_url。我曾经读过某个地方说混合使用GET和POST是不好的做法,但这种简单性对我来说是一个例外。


示例urls.py:

urlpatterns = [
    path('', HomeView.as_view(), name='home'),
    path('user/update/', UserUpdateView.as_view(), name='user_update'),
]

模板中链接到表单:

<a href="{% url 'user_update' %}?next={{ request.path }}">Update User</a>

基于类的视图:

class UserUpdateView(UpdateView):
    ...
    def get_success_url(self):
        return self.request.GET.get('next', reverse('home'))

在基于函数的视图中,您可以按以下方式使用它:
def createadv(request):
    uw = getuw(request.user.username)
    if request.method =='POST':
        form = AdverForm(request.POST, request.FILES)
        if form.is_valid():
            form.instance.user = request.user
            form.save()
            next = request.GET.get('next', reverse('home'))
            return HttpResponseRedirect(next)

    args = {}
    args.update(csrf(request))
    args['username'] = request.user.username
    args['form'] = AdverForm()
    args['uw'] = uw
    return  render_to_response('createadv.html', args)

我正在尝试使用LoginView实现这个功能,但它不起作用。我有一个导航栏出现在所有页面上。我添加了<a href="{% url 'sign in' %}?next={{ request.path }}">Sign in</a>。当点击导航栏上的“登录”按钮时,我看到这个http://127.0.0.1:8000/sign-in/?next=/vinyls/,但是当我输入我的用户名和密码并点击提交后,我被重定向到http://127.0.0.1:8000/accounts/profile。我尝试添加`def get_success_url(self): return self.request.GET.get('next', reverse('index'))` 但它将我重定向到主页。我做错了什么? - prsnr

2

使用 HTTP_REFERER 值:

  1. 在函数中使用 return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

  2. 在模板中使用 <a href="{{request.META.HTTP_REFERER}}">返回</a>


0
如果有人需要帮助,我已经在基于类的UpdateView中让它工作了。
模板
<form class="form" method="POST">
    {% csrf_token %}

    <!-- hidden form field -->
    <input type="hidden" id="previous_page" name="previous_page" 
    value="/previous/page/url">

    <!-- any other form fields -->
    {{ form.name|as_crispy_field }}
    {{ form.address|as_crispy_field }}

    <!-- form submit button -->
    <button class="btn btn-primary" type="submit" id="submit">Submit</button>
</form>


<!-- JS to insert previous page url in hidden input field -->
<script>
    prev = document.getElementById("previous_page");
    prev.value = document.referrer;
</script>


views.py

class ArticleUpdateView(generic.UpdateView):

    model = Article
    form_class = ArticleForm
    template_name = 'repo/article_form.html'

    def form_valid(self, form):
        form.instance.author = self.request.user
        # if form is valid get url of previous page from hidden input field
        # and assign to success url
        self.success_url = self.request.POST.get('previous_page')
        return super().form_valid(form)

视图现在将您重定向回您单击“更新/编辑”按钮的页面。任何URL查询参数也将被保留。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接