mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 07:57:55 +03:00 
			
		
		
		
	initial work on autodiscover
This commit is contained in:
		
							parent
							
								
									b71a24437a
								
							
						
					
					
						commit
						9f6d104dad
					
				|  | @ -1,3 +1,33 @@ | ||||||
| __version__ = '0.2.3' | __version__ = '0.2.3' | ||||||
| 
 | 
 | ||||||
| VERSION = __version__  # synonym | VERSION = __version__  # synonym | ||||||
|  | 
 | ||||||
|  | from djangorestframework.builtins import DjangoRestFrameworkApi | ||||||
|  | from django.utils.importlib import import_module | ||||||
|  | 
 | ||||||
|  | import imp | ||||||
|  | 
 | ||||||
|  | __all__ = ('autodiscover','api', '__version__', 'VERSION') | ||||||
|  | 
 | ||||||
|  | api = DjangoRestFrameworkApi() | ||||||
|  | 
 | ||||||
|  | def autodiscover(): | ||||||
|  |     """ | ||||||
|  |     Auto-discover INSTALLED_APPS api.py modules and fail silently when | ||||||
|  |     not present. This forces an import on them to register any api entries they | ||||||
|  |     may want. | ||||||
|  |     """ | ||||||
|  |     import copy | ||||||
|  |     from django.conf import settings | ||||||
|  |     from django.utils.importlib import import_module | ||||||
|  | 
 | ||||||
|  |     for app in settings.INSTALLED_APPS: | ||||||
|  |         # Attempt to import the app's gargoyle module. | ||||||
|  |         before_import_registry = copy.copy(api._registry) | ||||||
|  |         try: | ||||||
|  |             import_module('%s.api' % app) | ||||||
|  |         except: | ||||||
|  |             # Reset the model registry to the state before the last import as | ||||||
|  |             # this import will have to reoccur on the next request and this | ||||||
|  |             # could raise NotRegistered and AlreadyRegistered exceptions | ||||||
|  |             api._registry = before_import_registry | ||||||
|  |  | ||||||
							
								
								
									
										95
									
								
								djangorestframework/builtins.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								djangorestframework/builtins.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | ||||||
|  | from django.conf.urls.defaults import patterns, url, include | ||||||
|  | 
 | ||||||
|  | class ApiEntry(object): | ||||||
|  |     """ | ||||||
|  |     Hold information about a Resource in the api | ||||||
|  |     """ | ||||||
|  |      | ||||||
|  |     def __init__(self, resource, view, name, namespace=None): | ||||||
|  |         self.resource, self.view, self.name = resource, view, name | ||||||
|  |         self.namespace = namespace is not None and namespace or '' | ||||||
|  |          | ||||||
|  |     def get_urls(self): | ||||||
|  |         """ | ||||||
|  |         Create the URLs corresponding to this view. | ||||||
|  |         """ | ||||||
|  |         from djangorestframework.mixins import ListModelMixin, InstanceMixin | ||||||
|  |         if self.namespace == '': | ||||||
|  |             namespaced_name = self.name | ||||||
|  |         else: | ||||||
|  |             namespaced_name = '%s/%s' % (self.namespace, self.name) | ||||||
|  | 
 | ||||||
|  |         if issubclass(self.view, ListModelMixin): | ||||||
|  |             urlpatterns = patterns('', | ||||||
|  |                 url(r'^%s/$' % (namespaced_name), | ||||||
|  |                     self.view.as_view(resource=self.resource), | ||||||
|  |                     name=self.name, | ||||||
|  |                     ) | ||||||
|  |             ) | ||||||
|  |         elif issubclass(self.view, InstanceMixin): | ||||||
|  |             urlpatterns = patterns('', | ||||||
|  |                 url(r'^%s/(?P<pk>[0-9a-zA-Z]+)/$' % (namespaced_name), | ||||||
|  |                     self.view.as_view(resource=self.resource), | ||||||
|  |                     name=self.name + '_change', | ||||||
|  |                     ) | ||||||
|  |             ) | ||||||
|  |         return urlpatterns | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  |     def urls(self): | ||||||
|  |         return self.get_urls(), 'api', self.namespace | ||||||
|  |     urls = property(urls) | ||||||
|  | 
 | ||||||
|  | class DjangoRestFrameworkApi(object): | ||||||
|  |     app_name = 'api' | ||||||
|  |     namespace = 'api' | ||||||
|  | 
 | ||||||
|  |     def __init__(self, *args, **kwargs): | ||||||
|  |         self._registry = {} | ||||||
|  |         super(DjangoRestFrameworkApi, self).__init__(*args, **kwargs) | ||||||
|  | 
 | ||||||
|  |     def register(self, view, resource, namespace=None, name=None): | ||||||
|  |         """ | ||||||
|  |         Register a resource and a view into the API, optionally giving an  | ||||||
|  |         override for the resource's name and a namespace for the URLs. | ||||||
|  |         """ | ||||||
|  |         if name is None: | ||||||
|  |             if hasattr(resource, 'model'): | ||||||
|  |                 # Use the model's name as the resource_name | ||||||
|  |                 name = resource.model.__name__.lower() | ||||||
|  |             else: | ||||||
|  |                 # Use the Resource's name as the resource_name | ||||||
|  |                 name = resource.__name__.lower() | ||||||
|  |          | ||||||
|  |         resource.api_name = name | ||||||
|  |          | ||||||
|  |         if namespace not in self._registry: | ||||||
|  |             self._registry[namespace] = {} | ||||||
|  |              | ||||||
|  |         if name not in self._registry[namespace]: | ||||||
|  |             self._registry[namespace][name] = [] | ||||||
|  |              | ||||||
|  |         api_entry = ApiEntry(resource, view, name, namespace) | ||||||
|  |         self._registry[namespace][name].append(api_entry) | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def urls(self): | ||||||
|  |         return self.get_urls(), self.app_name, self.namespace | ||||||
|  |      | ||||||
|  |     def get_urls(self): | ||||||
|  |         """ | ||||||
|  |         Return all of the urls for this API | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |         # Site-wide views. | ||||||
|  |         urlpatterns = patterns('',) | ||||||
|  | 
 | ||||||
|  |         # Add in each resource's views. | ||||||
|  |         for namespace in self._registry.keys(): | ||||||
|  |             for resource_name in self._registry[namespace].keys(): | ||||||
|  |                 for api_entry in self._registry[namespace][resource_name]: | ||||||
|  |                     urlpatterns += patterns('', | ||||||
|  |                         url(r'^', include(api_entry.urls)) | ||||||
|  |                     ) | ||||||
|  |              | ||||||
|  |         return urlpatterns | ||||||
|  | @ -379,6 +379,16 @@ class ModelResource(FormResource): | ||||||
|                     return reverse(self.view_callable[0], kwargs=instance_attrs) |                     return reverse(self.view_callable[0], kwargs=instance_attrs) | ||||||
|                 except NoReverseMatch: |                 except NoReverseMatch: | ||||||
|                     pass |                     pass | ||||||
|  |                  | ||||||
|  |         if hasattr(self, 'api_name'): | ||||||
|  |             # Get the URL from the API | ||||||
|  |             try: | ||||||
|  |                 return reverse( | ||||||
|  |                     '%s:%s_change' % ('api', self.api_name), args=(instance.pk,) | ||||||
|  |                 ) | ||||||
|  |             except NoReverseMatch: | ||||||
|  |                 pass | ||||||
|  |                          | ||||||
|         raise _SkipField |         raise _SkipField | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										85
									
								
								djangorestframework/tests/api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								djangorestframework/tests/api.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | ||||||
|  | from django.test.testcases import TestCase | ||||||
|  | from djangorestframework.builtins import DjangoRestFrameworkApi | ||||||
|  | from djangorestframework.resources import Resource, ModelResource | ||||||
|  | from djangorestframework.tests.models import Company, Employee | ||||||
|  | from django.conf.urls.defaults import patterns, url, include | ||||||
|  | from djangorestframework.views import ListOrCreateModelView, InstanceModelView,\ | ||||||
|  |     ListModelView | ||||||
|  | from django.core.urlresolvers import reverse | ||||||
|  | 
 | ||||||
|  | __all__ = ('ApiTestCase',) | ||||||
|  | 
 | ||||||
|  | class CompanyResource(ModelResource): | ||||||
|  |     model = Company | ||||||
|  |      | ||||||
|  | class EmployeeResource(ModelResource): | ||||||
|  |     model = Employee | ||||||
|  |      | ||||||
|  | class UrlConfModule(object): | ||||||
|  |      | ||||||
|  |     def __init__(self, api): | ||||||
|  |         self.api = api | ||||||
|  |          | ||||||
|  |     def _get_urlpatterns(self): | ||||||
|  |         return patterns('',  | ||||||
|  |             url(r'^', include(self.api.urls)), | ||||||
|  |         ) | ||||||
|  |          | ||||||
|  |     urlpatterns = property(_get_urlpatterns) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ApiTestCase(TestCase): | ||||||
|  |      | ||||||
|  |     def setUp(self): | ||||||
|  |         self.api = DjangoRestFrameworkApi() | ||||||
|  |         self.urlconfmodule = UrlConfModule(self.api) | ||||||
|  |          | ||||||
|  |     def test_list_view(self): | ||||||
|  |         # Check that the URL gets registered | ||||||
|  |         self.api.register(ListModelView, CompanyResource) | ||||||
|  |         reverse('api:company', urlconf=self.urlconfmodule) | ||||||
|  |                  | ||||||
|  |     def test_instance_view(self): | ||||||
|  |         self.api.register(InstanceModelView, CompanyResource) | ||||||
|  |         company = Company(name='Acme Ltd') | ||||||
|  |         company.save() | ||||||
|  |         # Check that the URL gets registered | ||||||
|  |         reverse( | ||||||
|  |             'api:company_change', urlconf=self.urlconfmodule, | ||||||
|  |             kwargs={'pk':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(InstanceModelView, EmployeeResource) | ||||||
|  |         employee = Employee(employee_id='EMP001') | ||||||
|  |         employee.save() | ||||||
|  |         reverse( | ||||||
|  |             'api:employee_change', urlconf=self.urlconfmodule, | ||||||
|  |             kwargs={'pk':employee.employee_id} | ||||||
|  |         ) | ||||||
|  |          | ||||||
|  |     def test_with_different_name(self): | ||||||
|  |         self.api.register(InstanceModelView, CompanyResource, name='abcdef') | ||||||
|  |         company = Company(name='Acme Ltd') | ||||||
|  |         company.save() | ||||||
|  |         # Check that the URL gets registered | ||||||
|  |         reverse( | ||||||
|  |             'api:abcdef_change', urlconf=self.urlconfmodule, | ||||||
|  |             kwargs={'pk':company.id},  | ||||||
|  |         ) | ||||||
|  |          | ||||||
|  |     def test_with_prefix(self): | ||||||
|  |         self.api.register( | ||||||
|  |             InstanceModelView, CompanyResource, namespace='abcdef' | ||||||
|  |         ) | ||||||
|  |         company = Company(name='Acme Ltd') | ||||||
|  |         company.save() | ||||||
|  |         # Check that the URL gets registered | ||||||
|  |         reverse( | ||||||
|  |             'api:abcdef:company_change', urlconf=self.urlconfmodule, | ||||||
|  |             kwargs={'pk':company.id},  | ||||||
|  |         ) | ||||||
|  | @ -26,3 +26,9 @@ class UserGroupMap(models.Model): | ||||||
|         return ('user_group_map', (), { |         return ('user_group_map', (), { | ||||||
|             'pk': self.id |             '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)   | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user