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