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
|
# 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
|
||||||
|
|
|
@ -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…
Reference in New Issue