如何重定向与邮件数据(Django)

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

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

另外:

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

  • 我不能显示代码,因为它属于一个客户。

更新2: 我认为 KISS 是这里最好的原则。我已经把这两个应用程序合并成一个,使事情变得更简单、更健壮; 我应该能够说服客户这也是最好的方法。谢谢你的好评。如果我要像上面描述的那样维护两个应用程序,那么我认为会话将是实现这一点的方法——感谢 Matthew J Morrison 的建议。多亏了 Dzida,他的评论让我开始思考设计和简化的问题。

103916 次浏览

I think how I would probably handle this situation would be to save the post data in session, then remove it when I no longer need it. That way I can access the original post data after a redirect even though that post is gone.

Will that work for what you're trying to do?

Here is a code sample of what I'm suggesting: (keep in mind this is untested code)

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

One other thing to keep in mind... if you're doing this and also uploading files, i would not do it this way.

If you faced such problem there's a slight chance that you might need to revise your designs.

This is a restriction of HTTP that POST data cannot go with redirects.

Can you describe what are you trying to accomplish and maybe then we can think about some neat solution.

If you do not want use sessions as Matthew suggested you can pass POST params in GET to the new page (consider some limitations such as security and max length of GET params in query string).

UPDATE to your update:) It sounds strange to me that you have 2 web apps and those apps use one views.py (am I right?). Anyway consider passing your data from POST in GET to the proper view (in case data is not sensitive of course).

If you are using a redirect after processing the POST to AppB, you can actually get away with calling the AppB method from the AppA method.

An Example:

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/')

This should yield a transparent experience for the end-user, and the client who hired you will likely never know the difference.

If you're not redirecting after the POST, aren't you worried about duplicate data due to the user refreshing the page?

You need to use a HTTP 1.1 Temporary Redirect (307).

Unfortunately, Django redirect() and HTTPResponseRedirect (permanent) return only a 301 or 302. You have to implement it yourself:

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)

See also the django.http module.

Edit:

on recent Django versions, change iri_to_uri import to:

from django.utils.encoding import iri_to_uri

Just call your new view from your old view using the same request object. Of course it won't result in a redirect as such, but if all you care about is 'transferring' data from one view to the other, then it should work.
I tested the following snippet and it works.

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

You can use render and context with with it:

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

You can recive vars in template :

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

use requests package.Its very easy to implement

pip install requests

then you can call any urls with any method and transfer data

in your views import requests

import requests

to post data, follow the format

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

to get the absolute url in django view, use

request.build_absolute_uri(reverse('view_name'))

Thus the django view code looks like

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

where r is the response object with status_code and content attribute. r.status_code gives the status code(on success it will be 200) and r.content gives the body of response. There is a json method(r.json()) that will convert response to json format

requests

requests.post

I faced a similar issue recently.

Basically I had a form A, upon submitting it another form B would show up, which contains some results + a form. Upon submitting B, i wanted to display some alert to user and keep user on B only.

The way I solved this, is by displaying the results in a <output> field, in B.

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

And I used the same view for A->B and B->B. Now I just had to distinguish if the request is coming from A or B and render accordingly.

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})

But this only works if form B is small and not that dynamic.

You can redirect with session using request.session["key"] as shown below:

# "views.py"


from django.shortcuts import redirect


def my_view(request):
# Here
request.session["message"] = "success"
return redirect("https://example.com")
# "index.html"


\{\{ request.session.message }} {# success #}