I'm coding a plugin-wrapper for provide a app to restfull, problem is the app don't process PUT request, then I get from resfull a PUT request and should change request's method into a POST request.
I have tried this:
self.context['request'].method = 'POST'
but obviously don't works
How I could do it? Thanks
Serializer code:
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', )
View code:
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'])
I will divide my answer into 3 parts.
PART-1: Does Django Rest Framework (DRF) explicitly supports request method overriding?
Yes, DRF has provided 2 ways in which the request method can be overridden.
DRF supports browser-based PUT, DELETE and other methods, by overloading POST requests using a hidden form field.
For example:
<form action="/some/url" method="POST">
<input type="hidden" name="_method" value="PUT">
</form>
In the above example, we have overloaded the POST method with PUT by using the hidden form field with name as _method.
request.method will now return PUT instead of POST.
DRF also supports method overriding via the X-HTTP-Method-Override header. Just set the X-HTTP-Method-Override header with the value of the desired method.
For example, making a PATCH request via POST in jQuery:
$.ajax({
url: '/myresource/',
method: 'POST',
headers: {'X-HTTP-Method-Override': 'PATCH'},
...
});
This approach is useful when working with non-form content such as JSON or when working on an older web server and/or hosting provider that doesn't recognise particular HTTP methods such as PATCH.
PART-2: Why your code is not working?
Request method is stored in a variable _method and the property method is used to access the value of it.
Your way of setting value of request method would have worked had there been a setter defined for the request's _method attribute. Since it is not defined, you can't set the value of request method in the way you are doing.
PART-3: How to override the request method in your case?
Solution-1(Quick): Directly set the _method attribute
You can directly set the _method to your desired value which will override the request 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', )
This will override the request method to POST.
Solution-2: Set X-HTTP-Method-Override header in request via middleware
When initialize_request() is called in DRF view, DRF checks for X-HTTP-Method-Override header in the Django request. If it is set, it overrides the current request method to the method defined in that header.
So before DRF initializes and prepares a DRF request, we can set the X-HTTP-Method-Override header to our desired method which will override the request method.
We create a PutRequestMethodOverrideMiddleware class and set the X-HTTP-Method-Override header in the request in case the request is PUT and this particular header is not already set.
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
Then in your settings, add this middleware to your MIDDLEWARE_CLASSES.
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
...
...
# your custom middleware
'my_project.middlewares.PutRequestMethodOverrideMiddleware',
)
But remember, this method will override all the PUT requests method to POST method.
Here, PutRequestMethodOverrideMiddleware will be executed at the end. You can put it at the position you want it to execute.
As of version 3.3, DRF has dropped support for the method overloading mechanisms via both _method form field and X-HTTP-Method-Override header. You need to implement it yourself for the latest version.
The document provides an example by adding a custom middleware:
METHOD_OVERRIDE_HEADER = 'HTTP_X_HTTP_METHOD_OVERRIDE'
class MethodOverrideMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.method == 'POST' and METHOD_OVERRIDE_HEADER in request.META:
request.method = request.META[METHOD_OVERRIDE_HEADER]
return self.get_response(request)
Another solution is to override dispatch method in each of your APIView:
class MyView(APIView):
def dispatch(self, request, *args, **kwargs):
if request.method == 'POST' and METHOD_OVERRIDE_HEADER in request.META:
request.method = request.META[METHOD_OVERRIDE_HEADER]
return super().dispatch(request, *args, **kwargs)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With