Fixed #19414 -- Added admin registration decorator
Thanks stavros for the suggestion.
This commit is contained in:
parent
d1c9802811
commit
98514849dc
|
@ -1,5 +1,6 @@
|
|||
# ACTION_CHECKBOX_NAME is unused, but should stay since its import from here
|
||||
# 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.options import ModelAdmin, HORIZONTAL, VERTICAL
|
||||
from django.contrib.admin.options import StackedInline, TabularInline
|
||||
|
|
|
@ -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)
|
||||
|
||||
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
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -135,6 +135,10 @@ Minor features
|
|||
customize the value of :attr:`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`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -8,9 +8,15 @@ from django.db import models
|
|||
class Person(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
|
||||
|
||||
class Traveler(Person):
|
||||
pass
|
||||
|
||||
|
||||
class Location(models.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Place(Location):
|
||||
name = models.CharField(max_length=200)
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
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.test import TestCase
|
||||
|
||||
from .models import Person, Place, Location
|
||||
from .models import Person, Place, Location, Traveler
|
||||
|
||||
|
||||
class NameAdmin(admin.ModelAdmin):
|
||||
list_display = ['name']
|
||||
save_on_top = True
|
||||
|
||||
|
||||
class CustomSite(admin.AdminSite):
|
||||
pass
|
||||
|
||||
|
||||
class TestRegistration(TestCase):
|
||||
def setUp(self):
|
||||
self.site = admin.AdminSite()
|
||||
|
@ -62,3 +69,55 @@ class TestRegistration(TestCase):
|
|||
Refs #12004.
|
||||
"""
|
||||
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…
Reference in New Issue