mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-23 01:57:00 +03:00
Add override_method
context manager and cleanup.
This commit is contained in:
parent
18007d6846
commit
37e2720a40
|
@ -21,7 +21,7 @@ from rest_framework.compat import six
|
||||||
from rest_framework.compat import smart_text
|
from rest_framework.compat import smart_text
|
||||||
from rest_framework.compat import yaml
|
from rest_framework.compat import yaml
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.request import clone_request, is_form_media_type
|
from rest_framework.request import is_form_media_type, override_method
|
||||||
from rest_framework.utils import encoders
|
from rest_framework.utils import encoders
|
||||||
from rest_framework.utils.breadcrumbs import get_breadcrumbs
|
from rest_framework.utils.breadcrumbs import get_breadcrumbs
|
||||||
from rest_framework import exceptions, status, VERSION
|
from rest_framework import exceptions, status, VERSION
|
||||||
|
@ -456,18 +456,6 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
return False # Doesn't have permissions
|
return False # Doesn't have permissions
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _get_rendered_html_form(self, view, method, request):
|
|
||||||
# We need to impersonate a request with the correct method,
|
|
||||||
# so that eg. any dynamic get_serializer_class methods return the
|
|
||||||
# correct form for each method.
|
|
||||||
restore = view.request
|
|
||||||
request = clone_request(request, method)
|
|
||||||
view.request = request
|
|
||||||
try:
|
|
||||||
return self.get_rendered_html_form(view, method, request)
|
|
||||||
finally:
|
|
||||||
view.request = restore
|
|
||||||
|
|
||||||
def get_rendered_html_form(self, view, method, request):
|
def get_rendered_html_form(self, view, method, request):
|
||||||
"""
|
"""
|
||||||
Return a string representing a rendered HTML form, possibly bound to
|
Return a string representing a rendered HTML form, possibly bound to
|
||||||
|
@ -475,6 +463,7 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
|
|
||||||
In the absence of the View having an associated form then return None.
|
In the absence of the View having an associated form then return None.
|
||||||
"""
|
"""
|
||||||
|
with override_method(view, request, method) as request:
|
||||||
obj = getattr(view, 'object', None)
|
obj = getattr(view, 'object', None)
|
||||||
if not self.show_form_for_method(view, method, request, obj):
|
if not self.show_form_for_method(view, method, request, obj):
|
||||||
return
|
return
|
||||||
|
@ -482,7 +471,8 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
if method in ('DELETE', 'OPTIONS'):
|
if method in ('DELETE', 'OPTIONS'):
|
||||||
return True # Don't actually need to return a form
|
return True # Don't actually need to return a form
|
||||||
|
|
||||||
if not getattr(view, 'get_serializer', None) or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes):
|
if (not getattr(view, 'get_serializer', None)
|
||||||
|
or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes)):
|
||||||
return
|
return
|
||||||
|
|
||||||
serializer = view.get_serializer(instance=obj)
|
serializer = view.get_serializer(instance=obj)
|
||||||
|
@ -490,25 +480,13 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
form_renderer = self.form_renderer_class()
|
form_renderer = self.form_renderer_class()
|
||||||
return form_renderer.render(data, self.accepted_media_type, self.renderer_context)
|
return form_renderer.render(data, self.accepted_media_type, self.renderer_context)
|
||||||
|
|
||||||
def _get_raw_data_form(self, view, method, request, media_types):
|
|
||||||
# We need to impersonate a request with the correct method,
|
|
||||||
# so that eg. any dynamic get_serializer_class methods return the
|
|
||||||
# correct form for each method.
|
|
||||||
restore = view.request
|
|
||||||
request = clone_request(request, method)
|
|
||||||
view.request = request
|
|
||||||
try:
|
|
||||||
return self.get_raw_data_form(view, method, request, media_types)
|
|
||||||
finally:
|
|
||||||
view.request = restore
|
|
||||||
|
|
||||||
def get_raw_data_form(self, view, method, request, media_types):
|
def get_raw_data_form(self, view, method, request, media_types):
|
||||||
"""
|
"""
|
||||||
Returns a form that allows for arbitrary content types to be tunneled
|
Returns a form that allows for arbitrary content types to be tunneled
|
||||||
via standard HTML forms.
|
via standard HTML forms.
|
||||||
(Which are typically application/x-www-form-urlencoded)
|
(Which are typically application/x-www-form-urlencoded)
|
||||||
"""
|
"""
|
||||||
|
with override_method(view, request, method) as request:
|
||||||
# If we're not using content overloading there's no point in supplying a generic form,
|
# If we're not using content overloading there's no point in supplying a generic form,
|
||||||
# as the view won't treat the form's value as the content of the request.
|
# as the view won't treat the form's value as the content of the request.
|
||||||
if not (api_settings.FORM_CONTENT_OVERRIDE
|
if not (api_settings.FORM_CONTENT_OVERRIDE
|
||||||
|
@ -562,47 +540,20 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
request = renderer_context['request']
|
request = renderer_context['request']
|
||||||
response = renderer_context['response']
|
response = renderer_context['response']
|
||||||
|
|
||||||
obj = getattr(view, 'object', None)
|
|
||||||
if getattr(view, 'get_serializer', None):
|
|
||||||
serializer = view.get_serializer(instance=obj)
|
|
||||||
for field_name, field in serializer.fields.items():
|
|
||||||
if field.read_only:
|
|
||||||
del serializer.fields[field_name]
|
|
||||||
else:
|
|
||||||
serializer = None
|
|
||||||
|
|
||||||
parsers = []
|
|
||||||
for parser_class in view.parser_classes:
|
|
||||||
if is_form_media_type(parser_class.media_type):
|
|
||||||
continue
|
|
||||||
content = None
|
|
||||||
renderer_class = getattr(parser_class, 'renderer_class', None)
|
|
||||||
if renderer_class and serializer:
|
|
||||||
renderer = renderer_class()
|
|
||||||
context = renderer_context.copy()
|
|
||||||
context['indent'] = 4
|
|
||||||
content = renderer.render(serializer.data, accepted_media_type, context)
|
|
||||||
print content
|
|
||||||
parsers.append({
|
|
||||||
'media_type': parser_class.media_type,
|
|
||||||
'content': content
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
media_types = [parser.media_type for parser in view.parser_classes]
|
media_types = [parser.media_type for parser in view.parser_classes]
|
||||||
|
|
||||||
renderer = self.get_default_renderer(view)
|
renderer = self.get_default_renderer(view)
|
||||||
content = self.get_content(renderer, data, accepted_media_type, renderer_context)
|
content = self.get_content(renderer, data, accepted_media_type, renderer_context)
|
||||||
|
|
||||||
put_form = self._get_rendered_html_form(view, 'PUT', request)
|
put_form = self.get_rendered_html_form(view, 'PUT', request)
|
||||||
post_form = self._get_rendered_html_form(view, 'POST', request)
|
post_form = self.get_rendered_html_form(view, 'POST', request)
|
||||||
patch_form = self._get_rendered_html_form(view, 'PATCH', request)
|
patch_form = self.get_rendered_html_form(view, 'PATCH', request)
|
||||||
delete_form = self._get_rendered_html_form(view, 'DELETE', request)
|
delete_form = self.get_rendered_html_form(view, 'DELETE', request)
|
||||||
options_form = self._get_rendered_html_form(view, 'OPTIONS', request)
|
options_form = self.get_rendered_html_form(view, 'OPTIONS', request)
|
||||||
|
|
||||||
raw_data_put_form = self._get_raw_data_form(view, 'PUT', request, media_types)
|
raw_data_put_form = self.get_raw_data_form(view, 'PUT', request, media_types)
|
||||||
raw_data_post_form = self._get_raw_data_form(view, 'POST', request, media_types)
|
raw_data_post_form = self.get_raw_data_form(view, 'POST', request, media_types)
|
||||||
raw_data_patch_form = self._get_raw_data_form(view, 'PATCH', request, media_types)
|
raw_data_patch_form = self.get_raw_data_form(view, 'PATCH', request, media_types)
|
||||||
raw_data_put_or_patch_form = raw_data_put_form or raw_data_patch_form
|
raw_data_put_or_patch_form = raw_data_put_form or raw_data_patch_form
|
||||||
|
|
||||||
name = self.get_name(view)
|
name = self.get_name(view)
|
||||||
|
|
|
@ -28,6 +28,29 @@ def is_form_media_type(media_type):
|
||||||
base_media_type == 'multipart/form-data')
|
base_media_type == 'multipart/form-data')
|
||||||
|
|
||||||
|
|
||||||
|
class override_method(object):
|
||||||
|
"""
|
||||||
|
A context manager that temporarily overrides the method on a request,
|
||||||
|
additionally setting the `view.request` attribute.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
with override_method(view, request, 'POST') as request:
|
||||||
|
... # Do stuff with `view` and `request`
|
||||||
|
"""
|
||||||
|
def __init__(self, view, request, method):
|
||||||
|
self.view = view
|
||||||
|
self.request = request
|
||||||
|
self.method = method
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.view.request = clone_request(self.request, self.method)
|
||||||
|
return self.view.request
|
||||||
|
|
||||||
|
def __exit__(self, *args, **kwarg):
|
||||||
|
self.view.request = self.request
|
||||||
|
|
||||||
|
|
||||||
class Empty(object):
|
class Empty(object):
|
||||||
"""
|
"""
|
||||||
Placeholder for unset attributes.
|
Placeholder for unset attributes.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user