【问题标题】:Django: How do I redirect a post and pass on the post dataDjango:如何重定向帖子并传递帖子数据
【发布时间】:2011-03-02 17:41:05
【问题描述】:

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

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

还有:

  • 客户想要两个独立的应用程序,而不是将它们组合成一个。

  • 我无法显示属于客户端的代码。

更新 2: 我已经决定 KISS 是这里最好的原则。我将这两个应用程序合二为一,使事情变得更简单、更强大;我应该能够说服客户这也是最好的方法。感谢所有伟大的反馈。如果我要按照描述维护两个应用程序,那么我认为会话将​​是执行此操作的方法 - 感谢 Matthew J Morrison 的建议。感谢 Dzida,因为他的 cmets 让我想到了设计和简化。

【问题讨论】:

  • 你真的需要向客户端发送重定向,或者这可以通过调用一个函数并将所有发布数据传递给它来完成吗?
  • 我需要在客户端浏览器上更改 url,所以这是我能做到的唯一方法。
  • 你不能先对post数据做所有的处理,然后再重定向吗?
  • 我有类似的情况,但 POST 的数据要么与现有数据匹配,要么不匹配。如果匹配,我会获取该数据的 id,然后通过重定向中的 GET 变量将该 id 传递给脚本。我还将 POST 数据保存在 SESSION 中。现在重定向页面加载了 GET 中id 引用的数据,并且还可以访问 POST 提交的其他数据。

标签: django


【解决方案1】:

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

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

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

<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 较小且不那么动态的情况。

【讨论】:

    【解决方案2】:

    您需要使用HTTP 1.1 Temporary Redirect (307)。

    不幸的是,Django redirect()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 module

    编辑:

    在最近的 Django 版本中,将 iri_to_uri 导入更改为:

    from django.utils.encoding import iri_to_uri
    

    【讨论】:

    【解决方案3】:

    使用requests包。它很容易实现

    pip install requests
    

    然后你可以用任何方法调用任何url并传输数据

    在您看来导入请求

    import requests
    

    要发布数据,请遵循格式

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

    要在 django 视图中获取绝对 url,请使用

    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 格式

    requests

    requests.post

    【讨论】:

    • 我相信这不会改变用户浏览器中的 URL。听起来 OP 想要转发到一个新的 URL
    【解决方案4】:

    您可以将 rendercontext 与它一起使用:

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

    您可以在模板中接收变量:

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

    【讨论】:

      【解决方案5】:

      只需使用相同的请求对象从旧视图调用新视图。 当然,它不会导致重定向,但如果您关心的只是将数据从一个视图“传输”到另一个视图,那么它应该可以工作。
      我测试了以下 sn-p 并且它可以工作。

      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
      

      【讨论】:

      • 这是一个很酷的想法,但不会改变用户浏览器中的 URL。听起来 OP 想要转发到一个新的 URL。
      【解决方案6】:

      如果您遇到此类问题,您可能需要修改您的设计。

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

      你能描述一下你想要完成什么,也许我们可以考虑一些巧妙的解决方案。

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

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

      【讨论】:

      • 我可以看到他正在尝试做的事情可能是有效的,如果他试图处理过期登录,这将迫使用户在提交表单后登录......在这种情况下,他希望保留提交的数据,而不是强制用户在完成登录屏幕后重新输入所有内容。
      • 不确定我是否明白这一点,但在这种情况下,登录操作可以通过第一次查看来执行,几乎不需要修改代码,也不需要进行不必要的重定向。阅读现有代码以获得更准确的建议会很棒。
      • 我是说如果你提交了一个表单,但你没有登录,你将被重定向到一个登录表单……在那种情况下,你会失去它是你提交的。我同意能够看到一些现有的代码。
      • 用例是否有效不是由您决定的,我也面临同样的情况,在简单性和模块化方面,使用新 POST 进行重定向是完美的解决方案。跨度>
      【解决方案7】:

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

      这对你想做的事情有用吗?

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

      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
      

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

      【讨论】:

      • 我从未使用过会话,但我会看看,谢谢。
      • 这不是最佳做法,但仍然有帮助。我想对于这个问题,我们不会得到更漂亮的东西。
      • @GuilhermeDaviddaCosta 为什么你说这不是最佳实践?你能给我们一个提示吗?
      • 因为在会话中存储太多数据似乎不是一个好主意。但正如我所说,我想不出比这更漂亮的了。
      • 嗯,这取决于您存储会话的位置。最近我看到人们使用带有 memcached 的整个服务器进行会话和负载平衡(使用循环)每个请求。我不想给你我无法接受的建议,但我会将文件保存为临时文件,并在会话中只获得它的链接。这些天似乎没有人用完内存。
      【解决方案8】:

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

      一个例子:

      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 提议)不是吗?
      • 您可以选择以下三种方式之一。 #1,将数据存储在数据库中,并在重定向时传递新条目的pk。 #2,将数据存储在cache后端,并再次传递密钥。 #3,将其存储在会话中。任何这些对于网络应用程序来说都是完全正常的,即使它是暂时的。如果表单数据解析起来很重要,如果输出已经被缓存,它也会使系统更快。
      猜你喜欢
      • 2011-06-07
      • 2017-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多