aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--djangorestframework/mixins.py7
-rw-r--r--djangorestframework/tests/renderers.py2
-rw-r--r--djangorestframework/tests/views.py96
-rw-r--r--djangorestframework/views.py28
4 files changed, 125 insertions, 8 deletions
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index bb26ad96..a34b9230 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -452,7 +452,10 @@ class ResourceMixin(object):
return self._resource.filter_response(obj)
def get_bound_form(self, content=None, method=None):
- return self._resource.get_bound_form(content, method=method)
+ if hasattr(self._resource, 'get_bound_form'):
+ return self._resource.get_bound_form(content, method=method)
+ else:
+ return None
@@ -566,7 +569,7 @@ class UpdateModelMixin(object):
# TODO: update on the url of a non-existing resource url doesn't work correctly at the moment - will end up with a new url
try:
if args:
- # If we have any none kwargs then assume the last represents the primrary key
+ # If we have any none kwargs then assume the last represents the primary key
self.model_instance = model.objects.get(pk=args[-1], **kwargs)
else:
# Otherwise assume the kwargs uniquely identify the model
diff --git a/djangorestframework/tests/renderers.py b/djangorestframework/tests/renderers.py
index d2046212..e7091c69 100644
--- a/djangorestframework/tests/renderers.py
+++ b/djangorestframework/tests/renderers.py
@@ -223,4 +223,4 @@ if YAMLRenderer:
content = renderer.render(obj, 'application/yaml')
(data, files) = parser.parse(StringIO(content))
- self.assertEquals(obj, data) \ No newline at end of file
+ self.assertEquals(obj, data)
diff --git a/djangorestframework/tests/views.py b/djangorestframework/tests/views.py
index 598712d2..b0f9d6d4 100644
--- a/djangorestframework/tests/views.py
+++ b/djangorestframework/tests/views.py
@@ -1,17 +1,109 @@
from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from django.test import Client
+from django import forms
+from django.db import models
+from djangorestframework.views import View
+from djangorestframework.parsers import JSONParser
+from djangorestframework.resources import ModelResource
+from djangorestframework.views import ListOrCreateModelView, InstanceModelView
+
+from StringIO import StringIO
+
+
+class MockView(View):
+ """This is a basic mock view"""
+ pass
+
+class ResourceMockView(View):
+ """This is a resource-based mock view"""
+
+ class MockForm(forms.Form):
+ foo = forms.BooleanField(required=False)
+ bar = forms.IntegerField(help_text='Must be an integer.')
+ baz = forms.CharField(max_length=32)
+
+ form = MockForm
+
+class MockResource(ModelResource):
+ """This is a mock model-based resource"""
+
+ class MockResourceModel(models.Model):
+ foo = models.BooleanField()
+ bar = models.IntegerField(help_text='Must be an integer.')
+ baz = models.CharField(max_length=32, help_text='Free text. Max length 32 chars.')
+
+ model = MockResourceModel
+ fields = ('foo', 'bar', 'baz')
urlpatterns = patterns('djangorestframework.utils.staticviews',
url(r'^robots.txt$', 'deny_robots'),
url(r'^favicon.ico$', 'favicon'),
url(r'^accounts/login$', 'api_login'),
url(r'^accounts/logout$', 'api_logout'),
+ url(r'^mock/$', MockView.as_view()),
+ url(r'^resourcemock/$', ResourceMockView.as_view()),
+ url(r'^model/$', ListOrCreateModelView.as_view(resource=MockResource)),
+ url(r'^model/(?P<pk>[^/]+)/$', InstanceModelView.as_view(resource=MockResource)),
)
+class BaseViewTests(TestCase):
+ """Test the base view class of djangorestframework"""
+ urls = 'djangorestframework.tests.views'
+
+ def test_options_method_simple_view(self):
+ response = self.client.options('/mock/')
+ self._verify_options_response(response,
+ name='Mock',
+ description='This is a basic mock view')
+
+ def test_options_method_resource_view(self):
+ response = self.client.options('/resourcemock/')
+ self._verify_options_response(response,
+ name='Resource Mock',
+ description='This is a resource-based mock view',
+ fields={'foo':'BooleanField',
+ 'bar':'IntegerField',
+ 'baz':'CharField',
+ })
+
+ def test_options_method_model_resource_list_view(self):
+ response = self.client.options('/model/')
+ self._verify_options_response(response,
+ name='Mock List',
+ description='This is a mock model-based resource',
+ fields={'foo':'BooleanField',
+ 'bar':'IntegerField',
+ 'baz':'CharField',
+ })
+
+ def test_options_method_model_resource_detail_view(self):
+ response = self.client.options('/model/0/')
+ self._verify_options_response(response,
+ name='Mock Instance',
+ description='This is a mock model-based resource',
+ fields={'foo':'BooleanField',
+ 'bar':'IntegerField',
+ 'baz':'CharField',
+ })
+
+ def _verify_options_response(self, response, name, description, fields=None, status=200,
+ mime_type='application/json'):
+ self.assertEqual(response.status_code, status)
+ self.assertEqual(response['Content-Type'].split(';')[0], mime_type)
+ parser = JSONParser(None)
+ (data, files) = parser.parse(StringIO(response.content))
+ self.assertTrue('application/json' in data['renders'])
+ self.assertEqual(name, data['name'])
+ self.assertEqual(description, data['description'])
+ if fields is None:
+ self.assertFalse(hasattr(data, 'fields'))
+ else:
+ self.assertEqual(data['fields'], fields)
-class ViewTests(TestCase):
+
+class ExtraViewsTests(TestCase):
"""Test the extra views djangorestframework provides"""
urls = 'djangorestframework.tests.views'
@@ -39,5 +131,5 @@ class ViewTests(TestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'].split(';')[0], 'text/html')
-
# TODO: Add login/logout behaviour tests
+
diff --git a/djangorestframework/views.py b/djangorestframework/views.py
index 5f8e84cd..ffb389d9 100644
--- a/djangorestframework/views.py
+++ b/djangorestframework/views.py
@@ -13,6 +13,7 @@ from djangorestframework.compat import View as DjangoView
from djangorestframework.response import Response, ErrorResponse
from djangorestframework.mixins import *
from djangorestframework import resources, renderers, parsers, authentication, permissions, status
+from djangorestframework.utils.description import get_name, get_description
__all__ = (
@@ -140,8 +141,13 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
else:
response = Response(status.HTTP_204_NO_CONTENT)
- # Pre-serialize filtering (eg filter complex objects into natively serializable types)
- response.cleaned_content = self.filter_response(response.raw_content)
+ if request.method == 'OPTIONS':
+ # do not filter the response for HTTP OPTIONS, else the response fields are lost,
+ # as they do not correspond with model fields
+ response.cleaned_content = response.raw_content
+ else:
+ # Pre-serialize filtering (eg filter complex objects into natively serializable types)
+ response.cleaned_content = self.filter_response(response.raw_content)
except ErrorResponse, exc:
response = exc.response
@@ -156,7 +162,23 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
# merge with headers possibly set at some point in the view
response.headers.update(self.headers)
- return self.render(response)
+ return self.render(response)
+
+
+ def options(self, request, *args, **kwargs):
+ response_obj = {
+ 'name' : get_name(self),
+ 'description' : get_description(self),
+ 'renders': self._rendered_media_types,
+ 'parses': self._parsed_media_types,
+ }
+ form = self.get_bound_form()
+ if form is not None:
+ field_name_types = {}
+ for name, field in form.fields.iteritems():
+ field_name_types[name] = field.__class__.__name__
+ response_obj['fields'] = field_name_types
+ return response_obj
class ModelView(View):