made suggested fixes

This commit is contained in:
Sébastien Piquemal 2012-02-10 10:18:39 +02:00
parent 2cdff1b01e
commit db0b01037a
7 changed files with 34 additions and 45 deletions

View File

@ -43,7 +43,6 @@ class RequestMixin(object):
parser_classes = () parser_classes = ()
""" """
The set of parsers that the view can handle. The set of parsers that the view can handle.
Should be a tuple/list of classes as described in the :mod:`parsers` module. Should be a tuple/list of classes as described in the :mod:`parsers` module.
""" """
@ -54,22 +53,18 @@ class RequestMixin(object):
def get_parsers(self): def get_parsers(self):
""" """
Instantiates and returns the list of parsers that will be used by the request Instantiates and returns the list of parsers the request will use.
to parse its content.
""" """
if not hasattr(self, '_parsers'): return [p(self) for p in self.parser_classes]
self._parsers = [p(self) for p in self.parser_classes]
return self._parsers
def prepare_request(self, request): def create_request(self, request):
""" """
Prepares the request cycle. Returns an instance of :class:`request.Request`, Creates and returns an instance of :class:`request.Request`.
wrapping the original request object. This new instance wraps the `request` passed as a parameter, and use the
parsers set on the view.
""" """
parsers = self.get_parsers() parsers = self.get_parsers()
request = self.request_class(request, parsers=parsers) return self.request_class(request, parsers=parsers)
self.request = request
return request
@property @property
def _parsed_media_types(self): def _parsed_media_types(self):
@ -89,38 +84,29 @@ class ResponseMixin(object):
renderer_classes = () renderer_classes = ()
""" """
The set of response renderers that the view can handle. The set of response renderers that the view can handle.
Should be a tuple/list of classes as described in the :mod:`renderers` module. Should be a tuple/list of classes as described in the :mod:`renderers` module.
""" """
def get_renderers(self): def get_renderers(self):
""" """
Instantiates and returns the list of renderers that will be used to render Instantiates and returns the list of renderers the response will use.
the response.
""" """
if not hasattr(self, '_renderers'): return [r(self) for r in self.renderer_classes]
self._renderers = [r(self) for r in self.renderer_classes]
return self._renderers
def prepare_response(self, response): def prepare_response(self, response):
""" """
Prepares and returns `response`. Prepares and returns `response`.
This has no effect if the response is not an instance of :class:`response.Response`. This has no effect if the response is not an instance of :class:`response.Response`.
""" """
if hasattr(response, 'request') and response.request is None: if hasattr(response, 'request') and response.request is None:
response.request = self.request response.request = self.request
# Always add these headers. # set all the cached headers
response['Allow'] = ', '.join(allowed_methods(self))
# sample to allow caching using Vary http header
response['Vary'] = 'Authenticate, Accept'
# merge with headers possibly set at some point in the view
for name, value in self.headers.items(): for name, value in self.headers.items():
response[name] = value response[name] = value
# set the views renderers on the response # set the views renderers on the response
response.renderers = self.get_renderers() response.renderers = self.get_renderers()
self.response = response
return response return response
@property @property
@ -571,12 +557,12 @@ class PaginatorMixin(object):
page_num = int(self.request.GET.get('page', '1')) page_num = int(self.request.GET.get('page', '1'))
except ValueError: except ValueError:
raise ImmediateResponse( raise ImmediateResponse(
content={'detail': 'That page contains no results'}, {'detail': 'That page contains no results'},
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
if page_num not in paginator.page_range: if page_num not in paginator.page_range:
raise ImmediateResponse( raise ImmediateResponse(
content={'detail': 'That page contains no results'}, {'detail': 'That page contains no results'},
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
page = paginator.page(page_num) page = paginator.page(page_num)

View File

@ -89,7 +89,7 @@ class JSONParser(BaseParser):
return (json.load(stream), None) return (json.load(stream), None)
except ValueError, exc: except ValueError, exc:
raise ImmediateResponse( raise ImmediateResponse(
content={'detail': 'JSON parse error - %s' % unicode(exc)}, {'detail': 'JSON parse error - %s' % unicode(exc)},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -112,7 +112,7 @@ if yaml:
return (yaml.safe_load(stream), None) return (yaml.safe_load(stream), None)
except ValueError, exc: except ValueError, exc:
raise ImmediateResponse( raise ImmediateResponse(
content={'detail': 'YAML parse error - %s' % unicode(exc)}, {'detail': 'YAML parse error - %s' % unicode(exc)},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
else: else:
YAMLParser = None YAMLParser = None
@ -172,7 +172,7 @@ class MultiPartParser(BaseParser):
django_parser = DjangoMultiPartParser(self.view.request.META, stream, upload_handlers) django_parser = DjangoMultiPartParser(self.view.request.META, stream, upload_handlers)
except MultiPartParserError, exc: except MultiPartParserError, exc:
raise ImmediateResponse( raise ImmediateResponse(
content={'detail': 'multipart parse error - %s' % unicode(exc)}, {'detail': 'multipart parse error - %s' % unicode(exc)},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
return django_parser.parse() return django_parser.parse()

View File

@ -22,12 +22,12 @@ __all__ = (
_403_FORBIDDEN_RESPONSE = ImmediateResponse( _403_FORBIDDEN_RESPONSE = ImmediateResponse(
content={'detail': 'You do not have permission to access this resource. ' + {'detail': 'You do not have permission to access this resource. ' +
'You may need to login or otherwise authenticate the request.'}, 'You may need to login or otherwise authenticate the request.'},
status=status.HTTP_403_FORBIDDEN) status=status.HTTP_403_FORBIDDEN)
_503_SERVICE_UNAVAILABLE = ImmediateResponse( _503_SERVICE_UNAVAILABLE = ImmediateResponse(
content={'detail': 'request was throttled'}, {'detail': 'request was throttled'},
status=status.HTTP_503_SERVICE_UNAVAILABLE) status=status.HTTP_503_SERVICE_UNAVAILABLE)

View File

@ -166,9 +166,9 @@ class Request(object):
if parser.can_handle_request(content_type): if parser.can_handle_request(content_type):
return parser.parse(stream) return parser.parse(stream)
raise ImmediateResponse(content={'error': raise ImmediateResponse({
'Unsupported media type in request \'%s\'.' % content_type}, 'error': 'Unsupported media type in request \'%s\'.' % content_type},
status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE) status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)
@property @property
def _parsed_media_types(self): def _parsed_media_types(self):

View File

@ -174,7 +174,7 @@ class FormResource(Resource):
detail[u'field_errors'] = field_errors detail[u'field_errors'] = field_errors
# Return HTTP 400 response (BAD REQUEST) # Return HTTP 400 response (BAD REQUEST)
raise ImmediateResponse(content=detail, status=400) raise ImmediateResponse(detail, status=400)
def get_form_class(self, method=None): def get_form_class(self, method=None):
""" """

View File

@ -125,7 +125,7 @@ class Response(SimpleTemplateResponse):
return renderer, media_type return renderer, media_type
# No acceptable renderers were found # No acceptable renderers were found
raise ImmediateResponse(content={'detail': 'Could not satisfy the client\'s Accept header', raise ImmediateResponse({'detail': 'Could not satisfy the client\'s Accept header',
'available_types': self._rendered_media_types}, 'available_types': self._rendered_media_types},
status=status.HTTP_406_NOT_ACCEPTABLE, status=status.HTTP_406_NOT_ACCEPTABLE,
renderers=self.renderers) renderers=self.renderers)

View File

@ -173,7 +173,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
""" """
Return an HTTP 405 error if an operation is called which does not have a handler method. Return an HTTP 405 error if an operation is called which does not have a handler method.
""" """
raise ImmediateResponse(content= raise ImmediateResponse(
{'detail': 'Method \'%s\' not allowed on this resource.' % request.method}, {'detail': 'Method \'%s\' not allowed on this resource.' % request.method},
status=status.HTTP_405_METHOD_NOT_ALLOWED) status=status.HTTP_405_METHOD_NOT_ALLOWED)
@ -199,6 +199,12 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
""" """
# Restore script_prefix. # Restore script_prefix.
set_script_prefix(self.orig_prefix) set_script_prefix(self.orig_prefix)
# Always add these headers.
response['Allow'] = ', '.join(allowed_methods(self))
# sample to allow caching using Vary http header
response['Vary'] = 'Authenticate, Accept'
return response return response
# Note: session based authentication is explicitly CSRF validated, # Note: session based authentication is explicitly CSRF validated,
@ -211,7 +217,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
try: try:
# Get a custom request, built form the original request instance # Get a custom request, built form the original request instance
request = self.prepare_request(request) self.request = request = self.create_request(request)
# `initial` is the opportunity to temper with the request, # `initial` is the opportunity to temper with the request,
# even completely replace it. # even completely replace it.
@ -230,7 +236,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
response = handler(request, *args, **kwargs) response = handler(request, *args, **kwargs)
# Prepare response for the response cycle. # Prepare response for the response cycle.
response = self.prepare_response(response) self.response = response = self.prepare_response(response)
# Pre-serialize filtering (eg filter complex objects into natively serializable types) # Pre-serialize filtering (eg filter complex objects into natively serializable types)
# TODO: ugly hack to handle both HttpResponse and Response. # TODO: ugly hack to handle both HttpResponse and Response.
@ -241,7 +247,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
except ImmediateResponse, response: except ImmediateResponse, response:
# Prepare response for the response cycle. # Prepare response for the response cycle.
self.prepare_response(response) self.response = response = self.prepare_response(response)
# `final` is the last opportunity to temper with the response, or even # `final` is the last opportunity to temper with the response, or even
# completely replace it. # completely replace it.
@ -260,10 +266,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
for name, field in form.fields.iteritems(): for name, field in form.fields.iteritems():
field_name_types[name] = field.__class__.__name__ field_name_types[name] = field.__class__.__name__
content['fields'] = field_name_types content['fields'] = field_name_types
# Note 'ImmediateResponse' is misleading, it's just any response raise ImmediateResponse(content, status=status.HTTP_200_OK)
# that should be rendered and returned immediately, without any
# response filtering.
raise ImmediateResponse(content=content, status=status.HTTP_200_OK)
class ModelView(View): class ModelView(View):