【问题标题】:Django - Where are the params stored on a PUT/DELETE request?Django - PUT/DELETE 请求中存储的参数在哪里?
【发布时间】:2011-06-27 01:23:52
【问题描述】:

我想为我的新 django 项目遵循 RESTful 模式,并且我想知道在发出 PUT/DELETE 请求时参数在哪里。

据我所知,我只在请求中看到 GET 和 POST QueryDict,没有其​​他的。 Django 是否为请求添加了新的 PUT 或 DELETE QueryDict,还是将参数添加到 GET 或 POST QueryDict ?

感谢您的帮助。

【问题讨论】:

    标签: django rest parameters


    【解决方案1】:

    我正在使用 django v1.5。而我主要使用QueryDict来解决问题:

    from django.http import QueryDict
    put = QueryDict(request.body)
    description = put.get('description')
    

    在 *.coffee 中

    $.ajax
          url: "/policy/#{policyId}/description/"
          type: "PUT"
          data:
            description: value
          success: (data) ->
            alert data.body
          fail: (data) ->
            alert "fail"
    

    您可以去here 查找更多信息。我希望这可以帮助你。祝你好运:)

    【讨论】:

    • 对于现代版本的 Django,这比公认的答案更有帮助。
    • 当我 put = QueryDict(request.body) 时,它会打印为: 就像将我发送的数据保存为密钥一样。
    • 像“request.META.get('REQUEST_METHOD','').upper()”这样的东西不会像gist.github.com/g00fy-/1161423中提到的那样给我们'PUT'或'DELETE'吗?
    • 另外,我们是否需要执行类似“request.parse_file_upload(request.META,request)”之类的操作来解析“多部分”请求。
    • django 有点蹩脚,我们在 2017 年仍然必须使用这种解决方法。任何体面的 web 框架都应该嵌入这样的支持......
    【解决方案2】:

    我假设您要问的是您是否可以使用这样的方法:

    def restaction(request, id):
        if request.method == "PUT":
            someparam = request.PUT["somekey"]
    

    答案是否定的,你不能。 Django 不会为 PUT、OPTIONS 和 DELETE 请求构建这样的字典,原因正在解释 here

    总结一下,REST 的概念是,您交换的数据可能比简单的键值映射复杂得多。例如,放置图像,或使用 json。框架无法知道您可能想要发送数据的多种方式,因此它做了显而易见的事情 - 让您处理那一点。另请参阅this question 的答案,其中给出了相同的响应。

    现在,您在哪里找到数据?好吧,根据docs,django 1.2 的功能request.raw_post_data。作为提醒,it looks like django 1.3 will support request.read() 即类似文件的语义。

    【讨论】:

    • 从 Django 1.4 开始,request.raw_post_data 已重命名为 request.bodyraw_post_data 在 Django 1.6 中被删除。
    • 其实你可以让 Django 处理你喜欢的 PUT 和 DELETE 请求。在这里你可以找到possible approach
    • 谷歌线程中的这个 Malcom 至今不明白他在说什么,他的理由很荒谬。 11 年来 Django Core 团队甚至不敢实现这样的支持,这实在是太可怕了……
    【解决方案3】:

    Ninefiger 的回答是正确的。但是,有一些解决方法。

    如果您正在为 Django 项目编写 REST 风格的 API,我强烈建议您使用 tastypie。您将为自己节省大量时间,并保证您的 API 采用更结构化的形式。您还可以查看 sweetpie 是如何做到的(访问 PUT 和 DELETE 数据)。

    【讨论】:

    • 感谢链接,我去看看! :)
    【解决方案4】:

    我无法解决如何解析来自request 的multipart/form-data 的问题。 QueryDict(request.body) 没有帮助我。

    所以,我找到了适合我的解决方案。我开始使用这个:

    from django.http.multipartparser import MultiPartParser

    您可以从request 获取数据,例如:

    MultiPartParser(request.META, request, request.upload_handlers).parse()
    

    【讨论】:

    • 这在 Django 1.8 中对我有用。绝对是使用 PUT 处理文件上传时的最佳答案。
    【解决方案5】:

    您可以在django-piston's code 中查看为 PUT 方法获取 QueryDict 的示例(请参阅 coerce_put_post 方法)

    【讨论】:

      【解决方案6】:

      我的方法是重写调度函数,这样我就可以使用 QueryDict() 从正文数据中设置一个变量

      from django.contrib.auth.mixins import LoginRequiredMixin
      from django.http import QueryDict
      from django.views.generic import View
      
      
      class GenericView(View):
      
          def dispatch(self, request, *args, **kwargs):
              if request.method.lower() in self.http_method_names:
                  handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
      
                  # if we have a request with potential body data utilize QueryDict()
                  if request.method.lower() in ['post', 'put', 'patch']:
                      self.request_body_data = {k: v[0] if len(v)==1 else v for k, v in QueryDict(request.body).lists()}
              else:
                  handler = self.http_method_not_allowed
              return handler(request, *args, **kwargs)
      
      
      class ObjectDetailView(LoginRequiredMixin, GenericView):
      
          def put(self, request, object_id):
              print("updating object", object_id)
              print(self.request_body_data)
      
          def patch(self, request, object_id):
              print("updating object", object_id)
              print(self.request_body_data)
      
      

      【讨论】:

        【解决方案7】:

        Django 无法轻松访问PUT 请求正文中的参数。我的解决方法:

        def coerce_put_post(request):
        """
        Django doesn't particularly understand REST.
        In case we send data over PUT, Django won't
        actually look at the data and load it. We need
        to twist its arm here.
        
        The try/except abominiation here is due to a bug
        in mod_python. This should fix it.
        """
        if request.method == "PUT":
            # Bug fix: if _load_post_and_files has already been called, for
            # example by middleware accessing request.POST, the below code to
            # pretend the request is a POST instead of a PUT will be too late
            # to make a difference. Also calling _load_post_and_files will result 
            # in the following exception:
            #   AttributeError: You cannot set the upload handlers after the upload has been processed.
            # The fix is to check for the presence of the _post field which is set 
            # the first time _load_post_and_files is called (both by wsgi.py and 
            # modpython.py). If it's set, the request has to be 'reset' to redo
            # the query value parsing in POST mode.
            if hasattr(request, '_post'):
                del request._post
                del request._files
            
            try:
                request.method = "POST"
                request._load_post_and_files()
                #body = request.body
                request.method = "PUT"
            except AttributeError:
                request.META['REQUEST_METHOD'] = 'POST'
                request._load_post_and_files()
                request.META['REQUEST_METHOD'] = 'PUT'
                
            request.PUT = request.POST
        
        
        @api_view(["PUT", "POST"])
        def submit(request):
            coerce_put_post(request)
            description=request.PUT.get('k', 0)
            return HttpResponse(f"Received {description}")
        

        【讨论】:

          【解决方案8】:

          只要参数在 URL 中,仍然可以使用self.request.GET 获取 PUT 和 DELETE 方法的参数。

          例如

          DELETE /api/comment/?comment_id=40 HTTP/1.1
          

          在 APIView 中你可以这样做:

          class CommentAPIView(APIView):
          
              # ... ...
          
              def delete(self, request):
                  user = request.user.id
                  comment_id = self.request.GET['comment_id']
                  try:
                      cmt = get_object_or_404(Comment, id=comment_id, user=user)
                      cmt.delete()
                      return Response(status=204)
                  except Exception, e:
                      return Response({'error': str(e)})
          

          【讨论】:

            猜你喜欢
            • 2014-04-19
            • 1970-01-01
            • 2019-07-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-12
            • 2012-02-09
            相关资源
            最近更新 更多