Django:如何重定向帖子并传递帖子数据


79

在Django views.py文件中处理POST请求时,有时需要将其重定向到另一个URL。我重定向到的网址是由同一Django views.py文件中的另一个函数处理的。有办法做到这一点并维护原始POST数据吗?

更新:我为什么要这样做的更多解释。我有两个Web应用程序(我们称它们为AppA和AppB),它们接受用户输入到文本字段中的数据。当用户单击提交时,将处理数据并显示详细结果。AppA和AppB需要不同类型的数据。有时用户错误地将AppB类型数据发布到AppA。发生这种情况时,我想将它们重定向到AppB并显示AppB结果,或者至少用他们输入AppA的数据填充它。

也:

  • 客户需要两个单独的应用程序,而不是将它们组合为一个。

  • 我无法显示该代码,因为它属于客户端。

更新2:我认为在这里,KISS是最好的原则。我将这两个应用程序组合在一起,使事情变得更简单,更强大。我应该能够说服客户,这也是最好的方法。感谢您的宝贵意见。如果我要按所述维护两个应用程序,那么我想通过会议来做到这一点-感谢Matthew J Morrison提出的建议。感谢Dzida的意见,使我开始思考设计和简化。


您是否真的需要发送重定向到客户端,还是可以通过仅调用一个函数并将所有发布数据传递给客户端来完成此操作?
马修·J·莫里森

我需要在客户端的浏览器上更改url,因此这是我可以执行此操作的唯一方法。
FunLovinCoder 2010年

而且您不能先对发布数据进行所有处理,然后在事实发生之后进行重定向?
Matthew J Morrison 2010年

我有类似的情况,但是POST的数据与现有数据匹配或不匹配。如果匹配,则获取该数据的ID,然后通过重定向中的GET变量将该ID传递给脚本。我还将POST数据保存在SESSION中。现在,重定向的页面将加载idGET中引用的数据,并且还可以访问POST提交的其他数据。
Buttle Butkus 2014年

Answers:


55

如果您遇到此类问题,那么您可能需要修改设计的机会很小。

这是HTTP的限制,POST数据不能与重定向一起使用。

您能否描述您要完成的工作,然后我们可以考虑一些巧妙的解决方案。

如果您不希望按照Matthew的建议使用会话,则可以将GET中的POST参数传递到新页面(考虑一些限制,例如安全性和查询字符串中GET参数的最大长度)。

更新您的更新:)我有两个Web应用程序,而这些应用程序使用一个views.py(对吗?),这听起来让我感到奇怪。无论如何,请考虑将数据从GET中的POST传递到正确的视图(以防数据当然不敏感)。


2
我可以看到,如果他试图处理过期的登录名,而该登录名将迫使用户在提交表单后登录,那么他正在尝试执行的操作可能是有效的。提交的数据,并不会在完成登录屏幕后强制用户重新输入所有内容。
马修·J·莫里森

不知道我是否明白这一点,但在这种情况下,登录操作可以在不进行任何代码修改的情况下通过第一视图执行,而无需进行不必要的重定向。阅读exisitng代码以提出更准确的建议将非常有用。
dzida 2010年

我的意思是,如果您提交表单,但是您尚未登录,那么您将被重定向到登录表单...在这种情况下,您将丢失提交的所有内容。我同意能够看到一些现有代码。
马修·J·莫里森

1
由您决定用例是否有效,这取决于您,我面临着同样的情况,就简单性和模块化而言,使用新鲜POST进行重定向是完美的解决方案。
拉比·科迪

53

我认为如何处理这种情况将是在会话中保存帖子数据,然后在不再需要它时将其删除。这样,即使该帖子消失了,我也可以在重定向后访问原始帖子数据。

这对您想要的工作有用吗?

这是我建议的代码示例:(请记住,这是未经测试的代码)

def some_view(request):
    #do some stuff
    request.session['_old_post'] = request.POST
    return HttpResponseRedirect('next_view')

def next_view(request):
    old_post = request.session.get('_old_post')
    #do some stuff using old_post

要记住的另一件事...如果您正在执行此操作并且还上传了文件,则我不会这样做。


1
我从来没有使用过会议,但是我会感谢一下。
FunLovinCoder 2010年

1
这不是最佳做法,但仍然有帮助。我想对于这个问题,我们不会有任何更美的东西。
Guilherme David da Costa

@GuilhermeDaviddaCosta为什么您说这不是最佳实践?你能给我们一个提示吗?
Buttle Butkus 2014年

因为在会话中存储太多数据似乎不是一个好主意。但是正如我所说的,我想不到任何更漂亮的东西。
Guilherme David da Costa

4
好吧,这取决于您将会话存储在何处。最近,我看到人们使用带有memcached的整个服务器来进行会话和负载平衡(使用轮询)。我不想给您一些我无法忍受的建议,但是我会将文件另存为temp,并且在会话中仅获得其链接。这些天似乎没有人会用完RAM。
Guilherme David da Costa

23

您需要使用HTTP 1.1临时重定向 (307)。

不幸的是,Djangoredirect()HTTPResponseRedirect (永久)仅返回301或302。您必须自己实现它:

from django.http import HttpResponse, iri_to_uri
class HttpResponseTemporaryRedirect(HttpResponse):
    status_code = 307

    def __init__(self, redirect_to):
        HttpResponse.__init__(self)
        self['Location'] = iri_to_uri(redirect_to)

另请参见django.http模块

编辑:

在最新的Django版本上,将iri_to_uriimport更改为:

from django.utils.encoding import iri_to_uri

Django的较新版本的永久重定向HttpResponsePermanentRedirect,但不知道这是否解决了原来的问题docs.djangoproject.com/en/dev/ref/request-response/...
JiminyCricket

9

使用requests包。它非常容易实现

pip install requests

那么您可以使用任何方法调用任何网址并传输数据

在您看来导入请求

import requests

发布数据,请遵循以下格式

r = requests.post('http://yourdomain/path/', data = {'key':'value'})

要在Django视图中获取绝对网址,请使用

request.build_absolute_uri(reverse('view_name'))

因此,django视图代码看起来像

r = requests.post(
            request.build_absolute_uri(reverse('view_name')), 
            data = {'key':'value'}
    )

r带有status_codecontent属性的响应对象在哪里。 r.status_code给出状态代码(成功则为200)并r.content给出响应正文。有一个json方法(r.json())将响应转换为json格式

要求

request.post


4

只需使用相同的请求对象从旧视图中调用新视图即可。当然,它不会导致这样的重定向,但是,如果您关心的只是将数据从一个视图“传输”到另一个视图,则它应该可以工作。
我测试了以下代码段,它可以正常工作。

from django.views.generic import View

class MyOldView(View):
    def post(self, request):
        return MyNewView().post(request)

class MyNewView(View):
    def post(self, request):
        my_data = request.body
        print "look Ma; my data made it over here:", my_data

1
我正在使用此解决方案,并且没有任何问题。
吉瓦尔

1

您可以其与rendercontext一起使用:

Render(request,"your template path",        {'vad name' : var value}

您可以在template中获取vars:

{% If var name %}
 {{ var name }}
{% endif %}

1

我最近遇到了类似的问题。

基本上,我有一个表单A,提交后会显示另一个表单B,其中包含一些结果和一个表单。提交B后,我想向用户显示一些警报,并使用户仅停留在B上。

我解决此问题的方法是<output>在B字段中显示结果。

<output name="xyz" value="xyz">{{xyz}}</output>

我对A-> B和B-> B使用了相同的视图。现在,我只需要区分请求是来自A还是来自B并相应地进行呈现。

def view1(request):
    if "xyz" in request.POST:
        # request from B
        # do some processing
        return render(request, 'page.html', {"xyz":request.POST["xyz"]})
    else:
        # request from A
        res = foo() # some random function
        return render(request, 'page.html', {"xyz":res})

但这仅在表格B很小且不是那么动态的情况下有效。


0

如果您在处理POST到之后使用重定向AppB,则实际上可以AppBAppA方法中调用方法。

一个例子:

def is_appa_request(request):
    ## do some magic.
    return False or True
is_appb_request = is_appa_request

def AppA(request):
    if is_appb_request(request):
       return AppB(request)
    ## Process AppA.
    return HttpResponseRedirect('/appa/thank_you/')

def AppB(request):
    if is_appa_request(request):
       return AppA(request)
    ## Process AppB.
    return HttpResponseRedirect('/appb/thank_you/')

这应该为最终用户带来透明的体验,雇用您的客户可能永远不会知道区别。

如果您在POST之后没有重定向,您是否不担心由于用户刷新页面而导致重复数据?


如果这样的简单解决方案有效,那就太好了。但是,我需要在处理数据后显示详细的结果。这将需要会议(由Matthew J Morrison提议),不是吗?
FunLovinCoder 2010年

1
您可以通过以下三种方式之一进行操作。#1,将数据存储在数据库中,并pk在重定向时传递新条目的。#2,将数据存储在cache后端,然后再次传递密钥。#3,将其存储在会话中。对于网络应用程序,即使是暂时的,所有这些都是正常的。如果表单数据不是非平凡的解析,则如果已经缓存了输出,也将使系统更快。
杰克M.10年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.