diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index cec3f5aa67..3dc5075443 100644 --- a/django/contrib/admin/sites.py +++ b/django/contrib/admin/sites.py @@ -301,6 +301,7 @@ class AdminSite(object): 'site_header': self.site_header, 'site_url': self.site_url, 'has_permission': self.has_permission(request), + 'available_apps': self.get_app_list(request), } def password_change(self, request, extra_context=None): @@ -461,11 +462,10 @@ class AdminSite(object): return app_dict.get(label) return app_dict - @never_cache - def index(self, request, extra_context=None): + def get_app_list(self, request): """ - Displays the main admin index page, which lists all of the installed - apps that have been registered in this site. + Returns a sorted list of all the installed apps that have been + registered in this site. """ app_dict = self._build_app_dict(request) @@ -476,6 +476,16 @@ class AdminSite(object): for app in app_list: app['models'].sort(key=lambda x: x['name']) + return app_list + + @never_cache + def index(self, request, extra_context=None): + """ + Displays the main admin index page, which lists all of the installed + apps that have been registered in this site. + """ + app_list = self.get_app_list(request) + context = dict( self.each_context(request), title=self.index_title, diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index e620f34905..ce218f06dc 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -2507,11 +2507,32 @@ Templates can override or extend base admin templates as described in * ``site_title``: :attr:`AdminSite.site_title` * ``site_url``: :attr:`AdminSite.site_url` * ``has_permission``: :meth:`AdminSite.has_permission` + * ``available_apps``: a list of applications from the :doc:`application registry + ` available for the current user. Each entry in the + list is a dict representing an application with the following keys: + + * ``app_label``: the application label + * ``app_url``: the URL of the application index in the admin + * ``has_module_perms``: a boolean indicating if displaying and accessing of + the module's index page is permitted for the current user + * ``models``: a list of the models available in the application + + Each model is a dict with the following keys: + + * ``object_name``: class name of the model + * ``name``: plural name of the model + * ``perms``: a ``dict`` tracking ``add``, ``change``, and ``delete`` permissions + * ``admin_url``: admin changelist URL for the model + * ``add_url``: admin URL to add a new model instance .. versionchanged:: 1.8 The ``request`` argument and the ``has_permission`` variable were added. + .. versionchanged:: 1.9 + + The ``available_apps`` variable was added. + .. method:: AdminSite.has_permission(request) Returns ``True`` if the user for the given ``HttpRequest`` has permission diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index 99daac6a8f..8be0e334b8 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -48,6 +48,11 @@ Minor features changing the ``select_related()`` values used in the admin's changelist query based on the request. +* The ``available_apps`` context variable, which lists the available + applications for the current user, has been added to the + :meth:`AdminSite.each_context() ` + method. + :mod:`django.contrib.auth` ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/admin_views/test_adminsite.py b/tests/admin_views/test_adminsite.py new file mode 100644 index 0000000000..6e0fce57d8 --- /dev/null +++ b/tests/admin_views/test_adminsite.py @@ -0,0 +1,82 @@ +from __future__ import unicode_literals + +import datetime + +from django.conf.urls import include, url +from django.contrib import admin +from django.contrib.auth.models import User +from django.core.urlresolvers import reverse +from django.test import TestCase, override_settings +from django.test.client import RequestFactory + +from .models import Article + +site = admin.AdminSite(name="test_adminsite") +site.register(User) +site.register(Article) + +urlpatterns = [ + url(r'^test_admin/admin/', include(site.urls)), +] + + +@override_settings( + PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'], + ROOT_URLCONF="admin_views.test_adminsite", +) +class SiteEachContextTest(TestCase): + """ + Check each_context contains the documented variables and that available_apps context + variable structure is the expected one. + """ + @classmethod + def setUpTestData(cls): + cls.u1 = User.objects.create( + id=100, password='sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158', + last_login=datetime.datetime(2007, 5, 30, 13, 20, 10), is_superuser=True, username='super', + first_name='Super', last_name='User', email='super@example.com', + is_staff=True, is_active=True, date_joined=datetime.datetime(2007, 5, 30, 13, 20, 10), + ) + + def setUp(self): + factory = RequestFactory() + request = factory.get(reverse('test_adminsite:index')) + request.user = self.u1 + self.ctx = site.each_context(request) + + def test_each_context(self): + ctx = self.ctx + self.assertEqual(ctx['site_header'], 'Django administration') + self.assertEqual(ctx['site_title'], 'Django site admin') + self.assertEqual(ctx['site_url'], '/') + self.assertEqual(ctx['has_permission'], True) + + def test_available_apps(self): + ctx = self.ctx + apps = ctx['available_apps'] + # we have registered two models from two different apps + self.assertEqual(len(apps), 2) + + # admin_views.Article + admin_views = apps[0] + self.assertEqual(admin_views['app_label'], 'admin_views') + self.assertEqual(len(admin_views['models']), 1) + self.assertEqual(admin_views['models'][0]['object_name'], 'Article') + + # auth.User + auth = apps[1] + self.assertEqual(auth['app_label'], 'auth') + self.assertEqual(len(auth['models']), 1) + user = auth['models'][0] + self.assertEqual(user['object_name'], 'User') + + self.assertEqual(auth['app_url'], '/test_admin/admin/auth/') + self.assertEqual(auth['has_module_perms'], True) + + self.assertIn('perms', user) + self.assertEqual(user['perms']['add'], True) + self.assertEqual(user['perms']['change'], True) + self.assertEqual(user['perms']['delete'], True) + self.assertEqual(user['admin_url'], '/test_admin/admin/auth/user/') + self.assertEqual(user['add_url'], '/test_admin/admin/auth/user/add/') + self.assertEqual(user['name'], 'Users')