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

riz*_*tas 2 django django-rest-framework

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

我试过这个:

self.context['request'].method = 'POST'
Run Code Online (Sandbox Code Playgroud)

但显然不起作用

我怎么能这样做?谢谢

更新:

串行器代码:

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', )
Run Code Online (Sandbox Code Playgroud)

查看代码:

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'])
Run Code Online (Sandbox Code Playgroud)

Rah*_*pta 5

我将把答案分成3部分.

第1部分:DRF是否明确支持请求方法覆盖?

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

  1. 使用隐藏的表单字段:

DRF支持基于浏览器的PUT,DELETE和其他的方法,通过超载POST使用隐藏的表单字段的请求.

例如:

<form action="/some/url" method="POST">
    <input type="hidden" name="_method" value="PUT">
</form>
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,我们使用名称为的隐藏表单字段重载了POST方法.PUT_method

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

  1. 基于HTTP头的方法覆盖:

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

例如,PATCH通过POSTjQuery 发出请求:

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

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

第2部分:为什么你的代码不起作用?

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

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

第3部分:如何覆盖您案例中的请求方法?

Solution-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', )
Run Code Online (Sandbox Code Playgroud)

这将覆盖请求方法POST.

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

initialize_request()被称为在DRF视图,DRF检查X-HTTP-Method-Override在Django的请求报头.如果已设置,则它会覆盖当前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
Run Code Online (Sandbox Code Playgroud)

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

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    ...
    ...
    # your custom middleware 
    'my_project.middlewares.PutRequestMethodOverrideMiddleware',
)
Run Code Online (Sandbox Code Playgroud)

但请记住,此方法将覆盖方法的所有PUT请求POST方法.

在这里,PutRequestMethodOverrideMiddleware将在最后执行.您可以将它放在您希望它执行的位置.