This middleware allows developers to "fake" browser support for HTTP methods. Even though most modern browsers only support GET and POST, the HTTP standard defines others. In the context of REST, PUT and DELETE are used for client interaction with the server.
For forms with a PUT or DELETE method, this middleware will change them to go through POST, and will include an invisible field called "method_middleware_transform" that carries the originally intended method.
So, <form method="PUT" ...>...</form>
More or less becomes <form method="POST" ...><input type=hidden name="method_middleware_transform" value="PUT"></form>
(with a few other minor HTML modifications)
The process is completely transparent to the developer... you never have to deal with the fact that browsers don't support the standard methods.
One caveat is that server interaction via XMLHttpRequest
(AJAX) requires special attention... this middleware won't properly setup your XMLHttpRequest to take advantage of this functionality.
This is a combination of the work of Jesse Lovelace and the Django CSRF middleware.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import re
import itertools
_HTML_TYPES = ('text/html', 'application/xhtml+xml')
_SUPPORTED_TRANSFORMS = ['PUT', 'DELETE']
_FORM_RE = re.compile(r'((<form\W[^>]*\bmethod=(\'|"|))(%s)((\'|"|)\b[^>]*>))' % '|'.join(_SUPPORTED_TRANSFORMS), re.IGNORECASE)
_MIDDLEWARE_KEY = 'method_middleware_transform'
class HttpMethodsMiddleware(object):
def process_request(self, request):
if request.POST and request.POST.has_key(_MIDDLEWARE_KEY):
if request.POST[_MIDDLEWARE_KEY].upper() in _SUPPORTED_TRANSFORMS:
request.method = request.POST[_MIDDLEWARE_KEY]
return None
def process_response(self, request, response):
if response['Content-Type'].split(';')[0] in _HTML_TYPES:
# ensure we don't add the 'id' attribute twice (HTML validity)
idattributes = itertools.chain(("id='" + _MIDDLEWARE_KEY + "'",),
itertools.repeat(''))
def add_transform_field(match):
"""Returns the matched <form> tag with a modified method and
the added <input> element"""
return match.group(2) + "POST" + match.group(5) + \
"<div style='display:none;'>" + \
"<input type='hidden' " + idattributes.next() + \
" name='" + _MIDDLEWARE_KEY + "' value='" + \
match.group(4).upper() + "' /></div>"
# Modify any POST forms
response.content = _FORM_RE.sub(add_transform_field, response.content)
return response
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 1 week ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Be aware that this snippet as is can expose your application to CSRF attacks. Django's CSRF checks will always occur after this middleware is run, and it currently only checks
POST
requests.I've made some updates for our version of this snippet here (with more comments): https://github.com/bueda/django-comrade/commit/de4d38b0c503908f11d5d73a60e3beef4735997c
#
Please login first before commenting.