mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-23 06:29:58 +03:00
Implement routers and resources according to the documentation
This commit is contained in:
parent
d4f5c9cf5a
commit
ca5a3abca3
11
djangorestframework/resources.py
Normal file
11
djangorestframework/resources.py
Normal 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'
|
91
djangorestframework/routers.py
Normal file
91
djangorestframework/routers.py
Normal 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))
|
|
@ -91,6 +91,9 @@ INSTALLED_APPS = (
|
|||
# 'django.contrib.admindocs',
|
||||
'djangorestframework',
|
||||
'djangorestframework.tokenauth',
|
||||
|
||||
# Load up the models
|
||||
'djangorestframework.tests'
|
||||
)
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
|
|
@ -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)
|
||||
|
|
140
djangorestframework/tests/routers.py
Normal file
140
djangorestframework/tests/routers.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user