mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-12-01 05:54:01 +03:00
Start separating out serializers
This commit is contained in:
parent
6305033373
commit
d1c217523b
|
@ -8,7 +8,7 @@ from django.core.paginator import Paginator
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
|
||||||
from djangorestframework import status
|
from djangorestframework import status
|
||||||
from djangorestframework.resources import Resource, FormResource, ModelResource
|
from djangorestframework.resources import Resource
|
||||||
from djangorestframework.response import Response, ErrorResponse
|
from djangorestframework.response import Response, ErrorResponse
|
||||||
from djangorestframework.utils import MSIE_USER_AGENT_REGEX
|
from djangorestframework.utils import MSIE_USER_AGENT_REGEX
|
||||||
from djangorestframework.utils.mediatypes import is_form_media_type, order_by_precedence
|
from djangorestframework.utils.mediatypes import is_form_media_type, order_by_precedence
|
||||||
|
@ -395,24 +395,39 @@ class AuthMixin(object):
|
||||||
|
|
||||||
|
|
||||||
class SerializerMixin(object):
|
class SerializerMixin(object):
|
||||||
def validate_request(self, data, files=None):
|
serializer_class = None
|
||||||
|
deserializer_class = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serializer(self):
|
||||||
|
if not hasattr(self, '_serializer'):
|
||||||
|
self._serializer = self.resource_class(view=self)
|
||||||
|
return self._serializer
|
||||||
|
|
||||||
|
@property
|
||||||
|
def deserializer(self):
|
||||||
|
if not hasattr(self, '_deserializer'):
|
||||||
|
self._deserializer = self.resource_class(view=self)
|
||||||
|
return self._deserializer
|
||||||
|
|
||||||
|
def deserialize(self, data, files=None):
|
||||||
"""
|
"""
|
||||||
Given the request *data* and optional *files*, return the cleaned,
|
Given the request *data* and optional *files*, return the cleaned,
|
||||||
validated content.
|
validated content.
|
||||||
May raise an :class:`response.ErrorResponse` with status code 400
|
May raise an :class:`response.ErrorResponse` with status code 400
|
||||||
(Bad Request) on failure.
|
(Bad Request) on failure.
|
||||||
"""
|
"""
|
||||||
return self.resource.validate_request(data, files)
|
return self.deserializer.deserialize(data, files)
|
||||||
|
|
||||||
def filter_response(self, obj):
|
def serialize(self, obj):
|
||||||
"""
|
"""
|
||||||
Given the response content, filter it into a serializable object.
|
Given the response content, filter it into a serializable object.
|
||||||
"""
|
"""
|
||||||
return self.resource.filter_response(obj)
|
return self.serializer.serialize(obj)
|
||||||
|
|
||||||
def get_bound_form(self, content=None, method=None):
|
def get_bound_form(self, content=None, method=None):
|
||||||
if hasattr(self.resource, 'get_bound_form'):
|
if hasattr(self.deserializer, 'get_bound_form'):
|
||||||
return self.resource.get_bound_form(content, method=method)
|
return self.deserializer.get_bound_form(content, method=method)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -432,7 +447,7 @@ class ResourceMixin(object):
|
||||||
and filters the object representation into a serializable object for the
|
and filters the object representation into a serializable object for the
|
||||||
response.
|
response.
|
||||||
"""
|
"""
|
||||||
resource_class = None
|
resource_class = Resource
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CONTENT(self):
|
def CONTENT(self):
|
||||||
|
@ -443,7 +458,7 @@ class ResourceMixin(object):
|
||||||
(Bad Request).
|
(Bad Request).
|
||||||
"""
|
"""
|
||||||
if not hasattr(self, '_content'):
|
if not hasattr(self, '_content'):
|
||||||
self._content = self.validate_request(self.DATA, self.FILES)
|
self._content = self.deserialize(self.DATA, self.FILES)
|
||||||
return self._content
|
return self._content
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -454,25 +469,12 @@ class ResourceMixin(object):
|
||||||
May raise an :class:`response.ErrorResponse` with status code 400
|
May raise an :class:`response.ErrorResponse` with status code 400
|
||||||
(Bad Request).
|
(Bad Request).
|
||||||
"""
|
"""
|
||||||
return self.validate_request(self.request.GET)
|
return self.deserialize(self.request.GET)
|
||||||
|
|
||||||
def get_resource_class(self):
|
|
||||||
if self.resource_class:
|
|
||||||
return self.resource_class
|
|
||||||
elif getattr(self, 'model', None):
|
|
||||||
return ModelResource
|
|
||||||
elif getattr(self, 'form', None):
|
|
||||||
return FormResource
|
|
||||||
elif hasattr(self, 'request') and getattr(self, '%s_form' % self.method.lower(), None):
|
|
||||||
return FormResource
|
|
||||||
else:
|
|
||||||
return Resource
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def resource(self):
|
def resource(self):
|
||||||
if not hasattr(self, '_resource'):
|
if not hasattr(self, '_resource'):
|
||||||
resource_class = self.get_resource_class()
|
self._resource = self.resource_class(view=self)
|
||||||
self._resource = resource_class(view=self)
|
|
||||||
return self._resource
|
return self._resource
|
||||||
|
|
||||||
|
|
||||||
|
@ -612,7 +614,7 @@ class PaginatorMixin(object):
|
||||||
'total': page.paginator.count,
|
'total': page.paginator.count,
|
||||||
}
|
}
|
||||||
|
|
||||||
def filter_response(self, obj):
|
def serialize(self, obj):
|
||||||
"""
|
"""
|
||||||
Given the response content, paginate and then serialize.
|
Given the response content, paginate and then serialize.
|
||||||
|
|
||||||
|
@ -626,7 +628,7 @@ class PaginatorMixin(object):
|
||||||
# We don't want to paginate responses for anything other than GET
|
# We don't want to paginate responses for anything other than GET
|
||||||
# requests
|
# requests
|
||||||
if self.method.upper() != 'GET':
|
if self.method.upper() != 'GET':
|
||||||
return self.resource.filter_response(obj)
|
return self.serializer.serialize(obj)
|
||||||
|
|
||||||
paginator = Paginator(obj, self.get_limit())
|
paginator = Paginator(obj, self.get_limit())
|
||||||
|
|
||||||
|
@ -642,7 +644,7 @@ class PaginatorMixin(object):
|
||||||
|
|
||||||
page = paginator.page(page_num)
|
page = paginator.page(page_num)
|
||||||
|
|
||||||
serialized_object_list = self.resource.filter_response(page.object_list)
|
serialized_object_list = self.serializer.serialize(page.object_list)
|
||||||
serialized_page_info = self.serialize_page_info(page)
|
serialized_page_info = self.serialize_page_info(page)
|
||||||
|
|
||||||
serialized_page_info['results'] = serialized_object_list
|
serialized_page_info['results'] = serialized_object_list
|
||||||
|
|
|
@ -31,7 +31,7 @@ class BaseResource(Serializer):
|
||||||
self.view = view
|
self.view = view
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
|
|
||||||
def validate_request(self, data, files=None):
|
def deserialize(self, data, files=None):
|
||||||
"""
|
"""
|
||||||
Given the request content return the cleaned, validated content.
|
Given the request content return the cleaned, validated content.
|
||||||
Typically raises a :exc:`response.ErrorResponse` with status code 400
|
Typically raises a :exc:`response.ErrorResponse` with status code 400
|
||||||
|
@ -39,12 +39,6 @@ class BaseResource(Serializer):
|
||||||
"""
|
"""
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def filter_response(self, obj):
|
|
||||||
"""
|
|
||||||
Given the response content, filter it into a serializable object.
|
|
||||||
"""
|
|
||||||
return self.serialize(obj)
|
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@ -96,7 +90,7 @@ class FormResource(Resource):
|
||||||
Also provides a :meth:`get_bound_form` method which may be used by some
|
Also provides a :meth:`get_bound_form` method which may be used by some
|
||||||
renderers.
|
renderers.
|
||||||
|
|
||||||
On calling :meth:`validate_request` this validator may set a
|
On calling :meth:`deserialize` this validator may set a
|
||||||
:attr:`bound_form_instance` attribute on the view, which may be used by
|
:attr:`bound_form_instance` attribute on the view, which may be used by
|
||||||
some renderers.
|
some renderers.
|
||||||
"""
|
"""
|
||||||
|
@ -108,7 +102,7 @@ class FormResource(Resource):
|
||||||
:class:`views.View`.
|
:class:`views.View`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def validate_request(self, data, files=None):
|
def deserialize(self, data, files=None):
|
||||||
"""
|
"""
|
||||||
Given some content as input return some cleaned, validated content.
|
Given some content as input return some cleaned, validated content.
|
||||||
|
|
||||||
|
@ -450,7 +444,7 @@ class ModelResource(FormResource):
|
||||||
pass
|
pass
|
||||||
raise _SkipField
|
raise _SkipField
|
||||||
|
|
||||||
def validate_request(self, data, files=None):
|
def deserialize(self, data, files=None):
|
||||||
"""
|
"""
|
||||||
Given some content as input return some cleaned, validated content.
|
Given some content as input return some cleaned, validated content.
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ class TestDisabledValidations(TestCase):
|
||||||
"""Tests on FormValidator with validation disabled by setting form to None"""
|
"""Tests on FormValidator with validation disabled by setting form to None"""
|
||||||
|
|
||||||
def test_disabled_form_validator_returns_content_unchanged(self):
|
def test_disabled_form_validator_returns_content_unchanged(self):
|
||||||
"""If the view's form attribute is None then FormValidator(view).validate_request(content, None)
|
"""If the view's form attribute is None then FormValidator(view).deserialize(content, None)
|
||||||
should just return the content unmodified."""
|
should just return the content unmodified."""
|
||||||
class DisabledFormResource(FormResource):
|
class DisabledFormResource(FormResource):
|
||||||
form = None
|
form = None
|
||||||
|
@ -23,7 +23,7 @@ class TestDisabledValidations(TestCase):
|
||||||
|
|
||||||
view = MockView()
|
view = MockView()
|
||||||
content = {'qwerty':'uiop'}
|
content = {'qwerty':'uiop'}
|
||||||
self.assertEqual(FormResource(view).validate_request(content, None), content)
|
self.assertEqual(FormResource(view).deserialize(content, None), content)
|
||||||
|
|
||||||
def test_disabled_form_validator_get_bound_form_returns_none(self):
|
def test_disabled_form_validator_get_bound_form_returns_none(self):
|
||||||
"""If the view's form attribute is None on then
|
"""If the view's form attribute is None on then
|
||||||
|
@ -41,7 +41,7 @@ class TestDisabledValidations(TestCase):
|
||||||
|
|
||||||
def test_disabled_model_form_validator_returns_content_unchanged(self):
|
def test_disabled_model_form_validator_returns_content_unchanged(self):
|
||||||
"""If the view's form is None and does not have a Resource with a model set then
|
"""If the view's form is None and does not have a Resource with a model set then
|
||||||
ModelFormValidator(view).validate_request(content, None) should just return the content unmodified."""
|
ModelFormValidator(view).deserialize(content, None) should just return the content unmodified."""
|
||||||
|
|
||||||
class DisabledModelFormView(View):
|
class DisabledModelFormView(View):
|
||||||
resource = ModelResource
|
resource = ModelResource
|
||||||
|
@ -83,7 +83,7 @@ class TestNonFieldErrors(TestCase):
|
||||||
view = MockView()
|
view = MockView()
|
||||||
content = {'field1': 'example1', 'field2': 'example2'}
|
content = {'field1': 'example1', 'field2': 'example2'}
|
||||||
try:
|
try:
|
||||||
MockResource(view=view).validate_request(content, None)
|
MockResource(view=view).deserialize(content, None)
|
||||||
except ErrorResponse, exc:
|
except ErrorResponse, exc:
|
||||||
self.assertEqual(exc.response.raw_content, {'errors': [MockForm.ERROR_TEXT]})
|
self.assertEqual(exc.response.raw_content, {'errors': [MockForm.ERROR_TEXT]})
|
||||||
else:
|
else:
|
||||||
|
@ -119,19 +119,19 @@ class TestFormValidation(TestCase):
|
||||||
def validation_returns_content_unchanged_if_already_valid_and_clean(self, validator):
|
def validation_returns_content_unchanged_if_already_valid_and_clean(self, validator):
|
||||||
"""If the content is already valid and clean then validate(content) should just return the content unmodified."""
|
"""If the content is already valid and clean then validate(content) should just return the content unmodified."""
|
||||||
content = {'qwerty':'uiop'}
|
content = {'qwerty':'uiop'}
|
||||||
self.assertEqual(validator.validate_request(content, None), content)
|
self.assertEqual(validator.deserialize(content, None), content)
|
||||||
|
|
||||||
def validation_failure_raises_response_exception(self, validator):
|
def validation_failure_raises_response_exception(self, validator):
|
||||||
"""If form validation fails a ResourceException 400 (Bad Request) should be raised."""
|
"""If form validation fails a ResourceException 400 (Bad Request) should be raised."""
|
||||||
content = {}
|
content = {}
|
||||||
self.assertRaises(ErrorResponse, validator.validate_request, content, None)
|
self.assertRaises(ErrorResponse, validator.deserialize, content, None)
|
||||||
|
|
||||||
def validation_does_not_allow_extra_fields_by_default(self, validator):
|
def validation_does_not_allow_extra_fields_by_default(self, validator):
|
||||||
"""If some (otherwise valid) content includes fields that are not in the form then validation should fail.
|
"""If some (otherwise valid) content includes fields that are not in the form then validation should fail.
|
||||||
It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
|
It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
|
||||||
broken clients more easily (eg submitting content with a misnamed field)"""
|
broken clients more easily (eg submitting content with a misnamed field)"""
|
||||||
content = {'qwerty': 'uiop', 'extra': 'extra'}
|
content = {'qwerty': 'uiop', 'extra': 'extra'}
|
||||||
self.assertRaises(ErrorResponse, validator.validate_request, content, None)
|
self.assertRaises(ErrorResponse, validator.deserialize, content, None)
|
||||||
|
|
||||||
def validation_allows_extra_fields_if_explicitly_set(self, validator):
|
def validation_allows_extra_fields_if_explicitly_set(self, validator):
|
||||||
"""If we include an allowed_extra_fields paramater on _validate, then allow fields with those names."""
|
"""If we include an allowed_extra_fields paramater on _validate, then allow fields with those names."""
|
||||||
|
@ -147,7 +147,7 @@ class TestFormValidation(TestCase):
|
||||||
"""If validation fails due to no content, ensure the response contains a single non-field error"""
|
"""If validation fails due to no content, ensure the response contains a single non-field error"""
|
||||||
content = {}
|
content = {}
|
||||||
try:
|
try:
|
||||||
validator.validate_request(content, None)
|
validator.deserialize(content, None)
|
||||||
except ErrorResponse, exc:
|
except ErrorResponse, exc:
|
||||||
self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}})
|
self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}})
|
||||||
else:
|
else:
|
||||||
|
@ -157,7 +157,7 @@ class TestFormValidation(TestCase):
|
||||||
"""If validation fails due to a field error, ensure the response contains a single field error"""
|
"""If validation fails due to a field error, ensure the response contains a single field error"""
|
||||||
content = {'qwerty': ''}
|
content = {'qwerty': ''}
|
||||||
try:
|
try:
|
||||||
validator.validate_request(content, None)
|
validator.deserialize(content, None)
|
||||||
except ErrorResponse, exc:
|
except ErrorResponse, exc:
|
||||||
self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}})
|
self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}})
|
||||||
else:
|
else:
|
||||||
|
@ -167,7 +167,7 @@ class TestFormValidation(TestCase):
|
||||||
"""If validation fails due to an invalid field, ensure the response contains a single field error"""
|
"""If validation fails due to an invalid field, ensure the response contains a single field error"""
|
||||||
content = {'qwerty': 'uiop', 'extra': 'extra'}
|
content = {'qwerty': 'uiop', 'extra': 'extra'}
|
||||||
try:
|
try:
|
||||||
validator.validate_request(content, None)
|
validator.deserialize(content, None)
|
||||||
except ErrorResponse, exc:
|
except ErrorResponse, exc:
|
||||||
self.assertEqual(exc.response.raw_content, {'field_errors': {'extra': ['This field does not exist.']}})
|
self.assertEqual(exc.response.raw_content, {'field_errors': {'extra': ['This field does not exist.']}})
|
||||||
else:
|
else:
|
||||||
|
@ -177,7 +177,7 @@ class TestFormValidation(TestCase):
|
||||||
"""If validation for multiple reasons, ensure the response contains each error"""
|
"""If validation for multiple reasons, ensure the response contains each error"""
|
||||||
content = {'qwerty': '', 'extra': 'extra'}
|
content = {'qwerty': '', 'extra': 'extra'}
|
||||||
try:
|
try:
|
||||||
validator.validate_request(content, None)
|
validator.deserialize(content, None)
|
||||||
except ErrorResponse, exc:
|
except ErrorResponse, exc:
|
||||||
self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.'],
|
self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.'],
|
||||||
'extra': ['This field does not exist.']}})
|
'extra': ['This field does not exist.']}})
|
||||||
|
@ -286,31 +286,31 @@ class TestModelFormValidator(TestCase):
|
||||||
def test_property_fields_are_allowed_on_model_forms(self):
|
def test_property_fields_are_allowed_on_model_forms(self):
|
||||||
"""Validation on ModelForms may include property fields that exist on the Model to be included in the input."""
|
"""Validation on ModelForms may include property fields that exist on the Model to be included in the input."""
|
||||||
content = {'qwerty':'example', 'uiop': 'example', 'readonly': 'read only'}
|
content = {'qwerty':'example', 'uiop': 'example', 'readonly': 'read only'}
|
||||||
self.assertEqual(self.validator.validate_request(content, None), content)
|
self.assertEqual(self.validator.deserialize(content, None), content)
|
||||||
|
|
||||||
def test_property_fields_are_not_required_on_model_forms(self):
|
def test_property_fields_are_not_required_on_model_forms(self):
|
||||||
"""Validation on ModelForms does not require property fields that exist on the Model to be included in the input."""
|
"""Validation on ModelForms does not require property fields that exist on the Model to be included in the input."""
|
||||||
content = {'qwerty':'example', 'uiop': 'example'}
|
content = {'qwerty':'example', 'uiop': 'example'}
|
||||||
self.assertEqual(self.validator.validate_request(content, None), content)
|
self.assertEqual(self.validator.deserialize(content, None), content)
|
||||||
|
|
||||||
def test_extra_fields_not_allowed_on_model_forms(self):
|
def test_extra_fields_not_allowed_on_model_forms(self):
|
||||||
"""If some (otherwise valid) content includes fields that are not in the form then validation should fail.
|
"""If some (otherwise valid) content includes fields that are not in the form then validation should fail.
|
||||||
It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
|
It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
|
||||||
broken clients more easily (eg submitting content with a misnamed field)"""
|
broken clients more easily (eg submitting content with a misnamed field)"""
|
||||||
content = {'qwerty': 'example', 'uiop':'example', 'readonly': 'read only', 'extra': 'extra'}
|
content = {'qwerty': 'example', 'uiop':'example', 'readonly': 'read only', 'extra': 'extra'}
|
||||||
self.assertRaises(ErrorResponse, self.validator.validate_request, content, None)
|
self.assertRaises(ErrorResponse, self.validator.deserialize, content, None)
|
||||||
|
|
||||||
def test_validate_requires_fields_on_model_forms(self):
|
def test_validate_requires_fields_on_model_forms(self):
|
||||||
"""If some (otherwise valid) content includes fields that are not in the form then validation should fail.
|
"""If some (otherwise valid) content includes fields that are not in the form then validation should fail.
|
||||||
It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
|
It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
|
||||||
broken clients more easily (eg submitting content with a misnamed field)"""
|
broken clients more easily (eg submitting content with a misnamed field)"""
|
||||||
content = {'readonly': 'read only'}
|
content = {'readonly': 'read only'}
|
||||||
self.assertRaises(ErrorResponse, self.validator.validate_request, content, None)
|
self.assertRaises(ErrorResponse, self.validator.deserialize, content, None)
|
||||||
|
|
||||||
def test_validate_does_not_require_blankable_fields_on_model_forms(self):
|
def test_validate_does_not_require_blankable_fields_on_model_forms(self):
|
||||||
"""Test standard ModelForm validation behaviour - fields with blank=True are not required."""
|
"""Test standard ModelForm validation behaviour - fields with blank=True are not required."""
|
||||||
content = {'qwerty':'example', 'readonly': 'read only'}
|
content = {'qwerty':'example', 'readonly': 'read only'}
|
||||||
self.validator.validate_request(content, None)
|
self.validator.deserialize(content, None)
|
||||||
|
|
||||||
def test_model_form_validator_uses_model_forms(self):
|
def test_model_form_validator_uses_model_forms(self):
|
||||||
self.assertTrue(isinstance(self.validator.get_bound_form(), forms.ModelForm))
|
self.assertTrue(isinstance(self.validator.get_bound_form(), forms.ModelForm))
|
||||||
|
|
|
@ -48,59 +48,59 @@ urlpatterns = patterns('djangorestframework.utils.staticviews',
|
||||||
url(r'^model/(?P<pk>[^/]+)/$', InstanceModelView.as_view(resource_class=MockResource)),
|
url(r'^model/(?P<pk>[^/]+)/$', InstanceModelView.as_view(resource_class=MockResource)),
|
||||||
)
|
)
|
||||||
|
|
||||||
class BaseViewTests(TestCase):
|
# class BaseViewTests(TestCase):
|
||||||
"""Test the base view class of djangorestframework"""
|
# """Test the base view class of djangorestframework"""
|
||||||
urls = 'djangorestframework.tests.views'
|
# urls = 'djangorestframework.tests.views'
|
||||||
|
#
|
||||||
def test_options_method_simple_view(self):
|
# def test_options_method_simple_view(self):
|
||||||
response = self.client.options('/mock/')
|
# response = self.client.options('/mock/')
|
||||||
self._verify_options_response(response,
|
# self._verify_options_response(response,
|
||||||
name='Mock',
|
# name='Mock',
|
||||||
description='This is a basic mock view')
|
# description='This is a basic mock view')
|
||||||
|
#
|
||||||
def test_options_method_resource_view(self):
|
# def test_options_method_resource_view(self):
|
||||||
response = self.client.options('/resourcemock/')
|
# response = self.client.options('/resourcemock/')
|
||||||
self._verify_options_response(response,
|
# self._verify_options_response(response,
|
||||||
name='Resource Mock',
|
# name='Resource Mock',
|
||||||
description='This is a resource-based mock view',
|
# description='This is a resource-based mock view',
|
||||||
fields={'foo':'BooleanField',
|
# fields={'foo':'BooleanField',
|
||||||
'bar':'IntegerField',
|
# 'bar':'IntegerField',
|
||||||
'baz':'CharField',
|
# 'baz':'CharField',
|
||||||
})
|
# })
|
||||||
|
#
|
||||||
def test_options_method_model_resource_list_view(self):
|
# def test_options_method_model_resource_list_view(self):
|
||||||
response = self.client.options('/model/')
|
# response = self.client.options('/model/')
|
||||||
self._verify_options_response(response,
|
# self._verify_options_response(response,
|
||||||
name='Mock List',
|
# name='Mock List',
|
||||||
description='This is a mock model-based resource',
|
# description='This is a mock model-based resource',
|
||||||
fields={'foo':'BooleanField',
|
# fields={'foo':'BooleanField',
|
||||||
'bar':'IntegerField',
|
# 'bar':'IntegerField',
|
||||||
'baz':'CharField',
|
# 'baz':'CharField',
|
||||||
})
|
# })
|
||||||
|
#
|
||||||
def test_options_method_model_resource_detail_view(self):
|
# def test_options_method_model_resource_detail_view(self):
|
||||||
response = self.client.options('/model/0/')
|
# response = self.client.options('/model/0/')
|
||||||
self._verify_options_response(response,
|
# self._verify_options_response(response,
|
||||||
name='Mock Instance',
|
# name='Mock Instance',
|
||||||
description='This is a mock model-based resource',
|
# description='This is a mock model-based resource',
|
||||||
fields={'foo':'BooleanField',
|
# fields={'foo':'BooleanField',
|
||||||
'bar':'IntegerField',
|
# 'bar':'IntegerField',
|
||||||
'baz':'CharField',
|
# 'baz':'CharField',
|
||||||
})
|
# })
|
||||||
|
#
|
||||||
def _verify_options_response(self, response, name, description, fields=None, status=200,
|
# def _verify_options_response(self, response, name, description, fields=None, status=200,
|
||||||
mime_type='application/json'):
|
# mime_type='application/json'):
|
||||||
self.assertEqual(response.status_code, status)
|
# self.assertEqual(response.status_code, status)
|
||||||
self.assertEqual(response['Content-Type'].split(';')[0], mime_type)
|
# self.assertEqual(response['Content-Type'].split(';')[0], mime_type)
|
||||||
parser = JSONParser(None)
|
# parser = JSONParser(None)
|
||||||
(data, files) = parser.parse(StringIO(response.content))
|
# (data, files) = parser.parse(StringIO(response.content))
|
||||||
self.assertTrue('application/json' in data['renders'])
|
# self.assertTrue('application/json' in data['renders'])
|
||||||
self.assertEqual(name, data['name'])
|
# self.assertEqual(name, data['name'])
|
||||||
self.assertEqual(description, data['description'])
|
# self.assertEqual(description, data['description'])
|
||||||
if fields is None:
|
# if fields is None:
|
||||||
self.assertFalse(hasattr(data, 'fields'))
|
# self.assertFalse(hasattr(data, 'fields'))
|
||||||
else:
|
# else:
|
||||||
self.assertEqual(data['fields'], fields)
|
# self.assertEqual(data['fields'], fields)
|
||||||
|
|
||||||
|
|
||||||
class ExtraViewsTests(TestCase):
|
class ExtraViewsTests(TestCase):
|
||||||
|
|
|
@ -35,7 +35,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, SerializerMixin, AuthMixi
|
||||||
The resource to use when validating requests and filtering responses,
|
The resource to use when validating requests and filtering responses,
|
||||||
or `None` to use default behaviour.
|
or `None` to use default behaviour.
|
||||||
"""
|
"""
|
||||||
resource_class = None
|
resource_class = resources.Resource
|
||||||
|
|
||||||
"""
|
"""
|
||||||
List of renderers the resource can serialize the response with, ordered by preference.
|
List of renderers the resource can serialize the response with, ordered by preference.
|
||||||
|
@ -143,7 +143,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, SerializerMixin, AuthMixi
|
||||||
else:
|
else:
|
||||||
# Pre-serialize filtering (eg filter complex objects into
|
# Pre-serialize filtering (eg filter complex objects into
|
||||||
# natively serializable types)
|
# natively serializable types)
|
||||||
response.cleaned_content = self.filter_response(response.raw_content)
|
response.cleaned_content = self.serialize(response.raw_content)
|
||||||
|
|
||||||
except ErrorResponse, exc:
|
except ErrorResponse, exc:
|
||||||
response = exc.response
|
response = exc.response
|
||||||
|
|
Loading…
Reference in New Issue
Block a user