Implement routers and resources according to the documentation

This commit is contained in:
Mjumbe Wawatu Poe 2012-09-08 18:25:17 -04:00
parent d4f5c9cf5a
commit ca5a3abca3
5 changed files with 255 additions and 2 deletions

View File

@ -0,0 +1,11 @@
from djangorestframework.serializers import ModelSerializer
from djangorestframework.generics import RootAPIView, InstanceAPIView
class ModelResource (object):
serializer_class = ModelSerializer
collection_view_class = RootAPIView
instance_view_class = InstanceAPIView
collection_name = None
instance_name = None
id_field_name = 'pk'

View File

@ -0,0 +1,91 @@
from django.conf.urls import patterns, url
from djangorestframework.resources import ModelResource
class DefaultResourceRouter (object):
def __init__(self, resource=ModelResource):
self.resource = resource
self._registry = []
@property
def urls(self):
return self.get_urls()
def get_urls(self):
urls = []
for model, resource in self._registry:
urls += self.make_patterns(model, resource,
id_field_name=resource.id_field_name,
collection_name=resource.collection_name,
instance_name=resource.instance_name)
return patterns('', *urls)
def make_patterns(self, model, resource, id_field_name=None,
collection_name=None, instance_name=None):
patterns = []
# The collection_name is the path at the root of the resource. For
# example, say we have a Dog model, and a dog with id=1:
#
# http://api.example.com/dogs/1/
#
# The collection name is 'dogs'. This will default to the plural name
# for the model.
#
if collection_name is None:
collection_name = unicode(model._meta.verbose_name_plural)
# The instance_name is the name of one model instance, and is used as a
# prefix for internal URL names. For example, for out Dog model with
# instance_name 'dog', may have the following urls:
#
# url('dogs/', collection_view, name='dog_collection'),
# url('dogs/(P<pk>[^/])/)', instance_view, name='dog_instance'),
#
if instance_name is None:
instance_name = unicode(model._meta.verbose_name)
# The id_field_name is the name of the field that will identify a
# resource in the collection. For example, if we wanted our dogs
# identified by a 'slug' field, we would have:
#
# url('dogs/(P<slug>[^/])/)', instance_view, name='dog_instance'),
#
# and:
#
# http://api.example.com/dogs/fido/
#
if id_field_name is None:
id_field_name = u'pk'
# The collection
if resource.collection_view_class:
class CollectionView (resource, resource.collection_view_class):
pass
collection_view = CollectionView.as_view()
url_string = '^{0}/$'.format(collection_name)
patterns.append(
url(url_string, collection_view,
name='{0}_collection'.format(instance_name))
)
# The instance
if resource.instance_view_class:
class InstanceView (resource, resource.instance_view_class):
pass
instance_view = InstanceView.as_view()
url_string = '^{0}/(?P<{1}>[^/]+)/$'.format(collection_name, id_field_name)
patterns.append(
url(url_string, instance_view,
name='{0}_instance'.format(instance_name))
)
return patterns
def register(self, model, resource=None):
resource = resource or self.resource
self._registry.append((model, resource))

View File

@ -91,6 +91,9 @@ INSTALLED_APPS = (
# 'django.contrib.admindocs',
'djangorestframework',
'djangorestframework.tokenauth',
# Load up the models
'djangorestframework.tests'
)
STATIC_URL = '/static/'

View File

@ -19,10 +19,18 @@ class CustomUser(models.Model):
class UserGroupMap(models.Model):
user = models.ForeignKey(to=CustomUser)
group = models.ForeignKey(to=Group)
group = models.ForeignKey(to=Group)
@models.permalink
def get_absolute_url(self):
return ('user_group_map', (), {
'pk': self.id
})
class Company(models.Model):
name = models.CharField(max_length=20)
class Employee(models.Model):
employee_id = models.CharField(max_length=20, primary_key=True)

View File

@ -0,0 +1,140 @@
from django.test.testcases import TestCase
from djangorestframework.generics import RootAPIView, InstanceAPIView, ListAPIView, DetailAPIView
from djangorestframework.resources import ModelResource
from djangorestframework.routers import DefaultResourceRouter
from djangorestframework.serializers import Serializer, ModelSerializer
from djangorestframework.tests.models import Company, Employee
from django.conf.urls.defaults import patterns, url, include
from django.core.urlresolvers import reverse, NoReverseMatch
import random
import string
__all__ = ('DefaultResourceRouterTestCase',)
class DummyUrlConfModule(object):
def __init__(self, object_with_urls):
self._object_with_urls = object_with_urls
@property
def urlpatterns(self):
urlpatterns = patterns('',
url(r'^', include(self._object_with_urls.urls, namespace='api')),
)
return urlpatterns
class DefaultResourceRouterTestCase(TestCase):
def setUp(self):
self.api = DefaultResourceRouter()
self.urlconfmodule = DummyUrlConfModule(self.api)
def test_list_view(self):
# Check that the URL gets registered
self.api.register(Company)
list_url = reverse('api:company_collection', urlconf=self.urlconfmodule)
self.assertEqual(list_url, '/companys/')
def test_instance_view(self):
self.api.register(Company)
company = Company(name='Acme Ltd')
company.save()
# Check that the URL gets registered
instance_url = reverse(
'api:company_instance', urlconf=self.urlconfmodule,
kwargs={'pk':company.id},
)
self.assertEqual(instance_url, '/companys/' + str(company.id) + '/')
def test_instance_view_with_nonumeric_primary_key(self):
"""
Check that the api can properly reverse urls for models with
non-numeric primary keys
"""
self.api.register(Employee)
employee = Employee(employee_id='EMP001')
employee.save()
instance_url = reverse(
'api:employee_instance', urlconf=self.urlconfmodule,
kwargs={'pk':employee.employee_id}
)
self.assertEqual(instance_url, '/employees/EMP001/')
def test_with_different_name(self):
class CompanyResource (ModelResource):
id_field_name = 'name'
self.api.register(Company, CompanyResource)
company = Company(name='Acme')
company.save()
instance_url = reverse(
'api:company_instance', urlconf=self.urlconfmodule,
kwargs={'name':company.name},
)
self.assertEqual(instance_url, '/companys/Acme/')
def test_with_different_collection_name(self):
class CompanyResource (ModelResource):
collection_name = 'companies'
self.api.register(Company, CompanyResource)
list_url = reverse('api:company_collection', urlconf=self.urlconfmodule)
self.assertEqual(list_url, '/companies/')
instance_url = reverse('api:company_instance', urlconf=self.urlconfmodule, kwargs={'pk':1})
self.assertEqual(instance_url, '/companies/1/')
def test_with_default_collection_view_class(self):
self.api.register(Company)
company = Company(name='Acme Ltd')
company.save()
view = self.api.urls[0]._callback
self.assertIsInstance(view.cls_instance, RootAPIView)
self.assertIsInstance(view.cls_instance, ModelResource)
def test_with_default_instance_view_class(self):
self.api.register(Company)
view = self.api.urls[1]._callback
self.assertIsInstance(view.cls_instance, InstanceAPIView)
self.assertIsInstance(view.cls_instance, ModelResource)
def test_with_different_collection_view_class(self):
class CompanyResource(ModelResource):
collection_view_class = ListAPIView
self.api.register(Company, CompanyResource)
view = self.api.urls[0]._callback
self.assertIsInstance(view.cls_instance, ListAPIView)
self.assertIsInstance(view.cls_instance, ModelResource)
def test_with_different_instance_view_class(self):
class CompanyResource(ModelResource):
instance_view_class = DetailAPIView
self.api.register(Company, CompanyResource)
view = self.api.urls[1]._callback
self.assertIsInstance(view.cls_instance, DetailAPIView)
self.assertIsInstance(view.cls_instance, ModelResource)
def test_with_default_serializer_class(self):
self.api.register(Company)
view = self.api.urls[0]._callback
self.assertIs(view.cls_instance.serializer_class, ModelSerializer)
def test_with_different_serializer_class(self):
class CompanySerializer(Serializer):
pass
class CompanyResource(ModelResource):
serializer_class = CompanySerializer
self.api.register(Company, CompanyResource)
view = self.api.urls[0]._callback
self.assertIs(view.cls_instance.serializer_class, CompanySerializer)