mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +03:00
Added support for OPTIONS method, including a few unit tests
This commit is contained in:
parent
53fcf29081
commit
3b413dbb40
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
class ViewTests(TestCase):
|
||||
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 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -159,6 +165,22 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
|
|||
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):
|
||||
"""
|
||||
A RESTful view that maps to a model in the database.
|
||||
|
|
Loading…
Reference in New Issue
Block a user