如何在Django Rest Framework中覆盖请求方法(从'PUT'到'POST')

时间:2015-07-16 15:51:36

标签: django django-rest-framework

我正在编写一个插件包装器来提供apprestfull,问题是应用程序不处理PUT请求,然后我从resfull得到一个PUT请求并且应该更改请求的方法进入POST请求。

我试过这个:

self.context['request'].method = 'POST'

但显然不起作用

我怎么能这样做? 感谢

更新

串行器代码:

class PageEditSerializer(serializers.ModelSerializer):
    """
    Serializer Class to edit and delete a Page.
    """
    raw = serializers.CharField()

    def save(self):

        #no works
        self.context['request'].method = 'POST'

        """call to waliki new function"""
        views.edit(self.context['request'], self.instance.slug)

    class Meta():
        model = Page
        fields = ('id', 'title', 'slug', 'raw', )
        read_only_fields = ('id', 'slug', )

查看代码:

class PageEditView(generics.RetrieveUpdateAPIView):
    """
    A simple View to edit a Page.
    """
    lookup_field = 'slug'
    serializer_class = PageEditSerializer
    permission_classes = (permissions.AllowAny, )

    def get_queryset(self):
        return Page.objects.filter(slug=self.kwargs['slug'])

1 个答案:

答案 0 :(得分:5)

我将把答案分为三部分。

PART-1:Django Rest Framework(DRF)是否明确支持请求方法覆盖?

是的,DRF提供了两种可以覆盖请求方法的方法。

  1. 使用隐藏的表单字段:
  2. DRF通过使用隐藏表单字段重载PUT请求,支持基于浏览器的DELETEPOST和其他方法。

    例如:

    <form action="/some/url" method="POST">
        <input type="hidden" name="_method" value="PUT">
    </form>
    

    在上面的示例中,我们使用名为POST的隐藏表单字段将PUT方法与_method重叠。

    request.method现在将返回PUT而不是POST

    1. 基于HTTP标头的方法覆盖:
    2. DRF还支持通过X-HTTP-Method-Override标头覆盖方法。只需使用所需方法的值设置X-HTTP-Method-Override标题即可。

      例如,在jQuery中通过PATCH发出POST请求:

      $.ajax({
          url: '/myresource/',
          method: 'POST',
          headers: {'X-HTTP-Method-Override': 'PATCH'},
          ...
      });
      

      此方法在处理非形式内容(如JSON)或处理较旧的Web服务器和/或无法识别特定HTTP方法(如PATCH的托管服务提供商)时非常有用。

      第2部分:为什么您的代码无效?

      请求方法存储在变量_method中,属性method用于访问它的值。

      如果为请求的setter属性定义了_method,那么设置请求方法值的方法就会奏效。由于未定义,因此您无法以您的方式设置请求method的值。

      PART-3:如何覆盖您案例中的请求方法?

      解决方案-1(快速):直接设置_method属性

      您可以直接将_method设置为所需的值,该值将覆盖请求方法。

      class PageEditSerializer(serializers.ModelSerializer):
          """
          Serializer Class to edit and delete a Page.
          """
          raw = serializers.CharField()
      
          def save(self):
      
              self.context['request']._method = 'POST' # override the request method
      
              """call to waliki new function"""
              views.edit(self.context['request'], self.instance.slug)
      
          class Meta():
              model = Page
              fields = ('id', 'title', 'slug', 'raw', )
              read_only_fields = ('id', 'slug', )
      

      这会将请求方法覆盖为POST

      解决方案-2:通过中间件在请求中设置X-HTTP-Method-Override标头

      在DRF视图中调用initialize_request()时,DRF会检查Django请求中的X-HTTP-Method-Override标头。如果已设置,它将覆盖当前请求method到该标头中定义的方法。

      因此,在DRF初始化并准备DRF request之前,我们可以将X-HTTP-Method-Override标头设置为我们所需的方法,该方法将覆盖请求方法。

      我们创建了一个PutRequestMethodOverrideMiddleware类,并在请求为X-HTTP-Method-Override并且尚未设置此特定标头的情况下在请求中设置PUT标头。

      class PutRequestMethodOverrideMiddleware(object):  
      
          def process_request(self, request):  
              override_method = request.META.get('X-HTTP-Method-Override')
              if request.method=='PUT' and not override_method: 
                  # Override method in case of PUT requests and header not already set
                  request.META['X-HTTP-Method-Override'] = 'POST' # set to desired method value
              return
      

      然后在您的设置中,将此中间件添加到MIDDLEWARE_CLASSES

      MIDDLEWARE_CLASSES = (
          'django.middleware.common.CommonMiddleware',
          'django.middleware.csrf.CsrfViewMiddleware',
          ...
          ...
          # your custom middleware 
          'my_project.middlewares.PutRequestMethodOverrideMiddleware',
      )
      

      但请记住,此方法会将所有PUT请求方法覆盖为POST方法。

      此处,PutRequestMethodOverrideMiddleware将在最后执行。您可以将它放在您希望它执行的位置。