mirror of
				https://github.com/django/django.git
				synced 2025-11-04 13:39:16 +00:00 
			
		
		
		
	Fixed #19414 -- Added admin registration decorator
Thanks stavros for the suggestion.
This commit is contained in:
		
							parent
							
								
									d1c9802811
								
							
						
					
					
						commit
						98514849dc
					
				
					 6 changed files with 127 additions and 1 deletions
				
			
		| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
# ACTION_CHECKBOX_NAME is unused, but should stay since its import from here
 | 
					# ACTION_CHECKBOX_NAME is unused, but should stay since its import from here
 | 
				
			||||||
# has been referenced in documentation.
 | 
					# has been referenced in documentation.
 | 
				
			||||||
 | 
					from django.contrib.admin.decorators import register
 | 
				
			||||||
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
 | 
					from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
 | 
				
			||||||
from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL
 | 
					from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL
 | 
				
			||||||
from django.contrib.admin.options import StackedInline, TabularInline
 | 
					from django.contrib.admin.options import StackedInline, TabularInline
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										28
									
								
								django/contrib/admin/decorators.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								django/contrib/admin/decorators.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					def register(*models, **kwargs):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Registers the given model(s) classes and wrapped ModelAdmin class with
 | 
				
			||||||
 | 
					    admin site:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @register(Author)
 | 
				
			||||||
 | 
					    class AuthorAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    A kwarg of `site` can be passed as the admin site, otherwise the default
 | 
				
			||||||
 | 
					    admin site will be used.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    from django.contrib.admin import ModelAdmin
 | 
				
			||||||
 | 
					    from django.contrib.admin.sites import site, AdminSite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _model_admin_wrapper(admin_class):
 | 
				
			||||||
 | 
					        admin_site = kwargs.pop('site', site)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not isinstance(admin_site, AdminSite):
 | 
				
			||||||
 | 
					            raise ValueError('site must subclass AdminSite')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not issubclass(admin_class, ModelAdmin):
 | 
				
			||||||
 | 
					            raise ValueError('Wrapped class must sublcass ModelAdmin.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        admin_site.register(models, admin_class=admin_class)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return admin_class
 | 
				
			||||||
 | 
					    return _model_admin_wrapper
 | 
				
			||||||
| 
						 | 
					@ -101,6 +101,34 @@ Other topics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            admin.site.register(Author)
 | 
					            admin.site.register(Author)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The register decorator
 | 
				
			||||||
 | 
					----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. function:: register(*models, [site=django.admin.sites.site])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. versionadded:: 1.7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    There is also a decorator for registering your ``ModelAdmin`` classes::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        from django.contrib import admin
 | 
				
			||||||
 | 
					        from .models import Author
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @admin.register(Author)
 | 
				
			||||||
 | 
					        class AuthorAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    It is given one or more model classes to register with the ``ModelAdmin``
 | 
				
			||||||
 | 
					    and an optional keyword argument ``site`` if you are not using the default
 | 
				
			||||||
 | 
					    ``AdminSite``::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        from django.contrib import admin
 | 
				
			||||||
 | 
					        from .models import Author, Reader, Editor
 | 
				
			||||||
 | 
					        from myproject.admin_site import custom_admin_site
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @admin.register(Author, Reader, Editor, site=custom_admin_site)
 | 
				
			||||||
 | 
					        class PersonAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``ModelAdmin`` options
 | 
					``ModelAdmin`` options
 | 
				
			||||||
----------------------
 | 
					----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +135,10 @@ Minor features
 | 
				
			||||||
  customize the value of :attr:`ModelAdmin.fields
 | 
					  customize the value of :attr:`ModelAdmin.fields
 | 
				
			||||||
  <django.contrib.admin.ModelAdmin.fields>`.
 | 
					  <django.contrib.admin.ModelAdmin.fields>`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* In addition to the existing ``admin.site.register`` syntax, you can use the
 | 
				
			||||||
 | 
					  new :func:`~django.contrib.admin.register` decorator to register a
 | 
				
			||||||
 | 
					  :class:`~django.contrib.admin.ModelAdmin`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:mod:`django.contrib.auth`
 | 
					:mod:`django.contrib.auth`
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,9 +8,15 @@ from django.db import models
 | 
				
			||||||
class Person(models.Model):
 | 
					class Person(models.Model):
 | 
				
			||||||
    name = models.CharField(max_length=200)
 | 
					    name = models.CharField(max_length=200)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Traveler(Person):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Location(models.Model):
 | 
					class Location(models.Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        abstract = True
 | 
					        abstract = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Place(Location):
 | 
					class Place(Location):
 | 
				
			||||||
    name = models.CharField(max_length=200)
 | 
					    name = models.CharField(max_length=200)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,23 @@
 | 
				
			||||||
from __future__ import unicode_literals
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib import admin
 | 
					from django.contrib import admin
 | 
				
			||||||
 | 
					from django.contrib.admin.decorators import register
 | 
				
			||||||
 | 
					from django.contrib.admin.sites import site
 | 
				
			||||||
from django.core.exceptions import ImproperlyConfigured
 | 
					from django.core.exceptions import ImproperlyConfigured
 | 
				
			||||||
from django.test import TestCase
 | 
					from django.test import TestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Person, Place, Location
 | 
					from .models import Person, Place, Location, Traveler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NameAdmin(admin.ModelAdmin):
 | 
					class NameAdmin(admin.ModelAdmin):
 | 
				
			||||||
    list_display = ['name']
 | 
					    list_display = ['name']
 | 
				
			||||||
    save_on_top = True
 | 
					    save_on_top = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CustomSite(admin.AdminSite):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestRegistration(TestCase):
 | 
					class TestRegistration(TestCase):
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        self.site = admin.AdminSite()
 | 
					        self.site = admin.AdminSite()
 | 
				
			||||||
| 
						 | 
					@ -62,3 +69,55 @@ class TestRegistration(TestCase):
 | 
				
			||||||
        Refs #12004.
 | 
					        Refs #12004.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.assertRaises(ImproperlyConfigured, self.site.register, Location)
 | 
					        self.assertRaises(ImproperlyConfigured, self.site.register, Location)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestRegistrationDecorator(TestCase):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Tests the register decorator in admin.decorators
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    For clarity:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @register(Person)
 | 
				
			||||||
 | 
					        class AuthorAdmin(ModelAdmin):
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    is functionally equal to (the way it is written in these tests):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        AuthorAdmin = register(Person)(AuthorAdmin)
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self.default_site = site
 | 
				
			||||||
 | 
					        self.custom_site = CustomSite()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_basic_registration(self):
 | 
				
			||||||
 | 
					        register(Person)(NameAdmin)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            isinstance(self.default_site._registry[Person],
 | 
				
			||||||
 | 
					                       admin.options.ModelAdmin)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_custom_site_registration(self):
 | 
				
			||||||
 | 
					        register(Person, site=self.custom_site)(NameAdmin)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            isinstance(self.custom_site._registry[Person],
 | 
				
			||||||
 | 
					                       admin.options.ModelAdmin)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_multiple_registration(self):
 | 
				
			||||||
 | 
					        register(Traveler, Place)(NameAdmin)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            isinstance(self.default_site._registry[Traveler],
 | 
				
			||||||
 | 
					                       admin.options.ModelAdmin)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            isinstance(self.default_site._registry[Place],
 | 
				
			||||||
 | 
					                       admin.options.ModelAdmin)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_wrapped_class_not_a_model_admin(self):
 | 
				
			||||||
 | 
					        self.assertRaisesMessage(ValueError, 'Wrapped class must sublcass ModelAdmin.',
 | 
				
			||||||
 | 
					            register(Person), CustomSite)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_custom_site_not_an_admin_site(self):
 | 
				
			||||||
 | 
					        self.assertRaisesMessage(ValueError, 'site must subclass AdminSite',
 | 
				
			||||||
 | 
					            register(Person, site=Traveler), NameAdmin)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue