From e7df67e150780d156508f527bee0b68c72f668c4 Mon Sep 17 00:00:00 2001 From: arthur Date: Sun, 8 May 2016 02:22:49 +0200 Subject: [PATCH] Update create_view_permission and move signal to AppConfig --- djadmin2/apps.py | 14 +++++++++ djadmin2/models.py | 9 ------ djadmin2/permissions.py | 63 +++++++++++++++++++++++++++-------------- 3 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 djadmin2/apps.py diff --git a/djadmin2/apps.py b/djadmin2/apps.py new file mode 100644 index 0000000..16eab43 --- /dev/null +++ b/djadmin2/apps.py @@ -0,0 +1,14 @@ +from django.apps import AppConfig +from django.db.models.signals import post_migrate +from django.utils.translation import ugettext_lazy as _ + +from djadmin2.permissions import create_view_permissions + + +class Djadmin2Config(AppConfig): + name = 'djadmin2' + verbose_name = _("Django Admin2") + + def ready(self): + post_migrate.connect(create_view_permissions, + dispatch_uid="django-admin2.djadmin2.permissions.create_view_permissions") diff --git a/djadmin2/models.py b/djadmin2/models.py index 8c8b81e..0cb781b 100644 --- a/djadmin2/models.py +++ b/djadmin2/models.py @@ -5,13 +5,11 @@ from __future__ import division, absolute_import, unicode_literals from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.db import models -from django.db.models import signals from django.utils.encoding import force_text from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import smart_text from django.utils.translation import ugettext, ugettext_lazy as _ -from . import permissions from .utils import quote @@ -99,10 +97,3 @@ class LogEntry(models.Model): quote(self.object_id) ) return None - -# setup signal handlers here, since ``models.py`` will be imported by django -# for sure if ``djadmin2`` is listed in the ``INSTALLED_APPS``. - -signals.post_migrate.connect( - permissions.create_view_permissions, - dispatch_uid="django-admin2.djadmin2.permissions.create_view_permissions") diff --git a/djadmin2/permissions.py b/djadmin2/permissions.py index 359aab4..7624a6c 100644 --- a/djadmin2/permissions.py +++ b/djadmin2/permissions.py @@ -20,15 +20,13 @@ from __future__ import division, absolute_import, unicode_literals import logging import re +from django.db.utils import DEFAULT_DB_ALIAS from django.apps import apps -from django.contrib.auth import models as auth_models -from django.contrib.contenttypes import models as contenttypes_models +from django.core.exceptions import ValidationError +from django.db import router from django.utils import six from django.utils.encoding import python_2_unicode_compatible, force_text -from . import utils - - logger = logging.getLogger('djadmin2') @@ -369,7 +367,7 @@ class TemplatePermissionChecker(object): return force_text(bool(self)) -def create_view_permissions(app_config, created_models=None, verbosity=2, **kwargs): +def create_view_permissions(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs): # noqa """ Create 'view' permissions for all models. @@ -377,40 +375,63 @@ def create_view_permissions(app_config, created_models=None, verbosity=2, **kwar Since we want to support read-only views, we need to add our own permission. - Copied from ``django.contrib.auth.management.create_permissions``. - """ - # Is there any reason for doing this import here? + Copied from ``https://github.com/django/django/blob/1.9.6/django/contrib/auth/management/__init__.py#L60``. - app_models = apps.get_models(app_config) + """ + if not app_config.models_module: + return + + try: + Permission = apps.get_model('auth', 'Permission') + except LookupError: + return + + if not router.allow_migrate_model(using, Permission): + return + + from django.contrib.contenttypes.models import ContentType # This will hold the permissions we're looking for as # (content_type, (codename, name)) searched_perms = list() # The codenames and ctypes that should exist. ctypes = set() - for klass in app_models: - ctype = contenttypes_models.ContentType.objects.get_for_model(klass) + for klass in app_config.get_models(): + # Force looking up the content types in the current database + # before creating foreign keys to them. + ctype = ContentType.objects.db_manager(using).get_for_model(klass) ctypes.add(ctype) - - opts = utils.model_options(klass) - perm = ('view_%s' % opts.object_name.lower(), u'Can view %s' % opts.verbose_name_raw) + perm = ('view_%s' % klass.object_name.lower(), u'Can view %s' % klass._meta.verbose_name_raw) searched_perms.append((ctype, perm)) # Find all the Permissions that have a content_type for a model we're # looking for. We don't need to check for codenames since we already have # a list of the ones we're going to create. - all_perms = set(auth_models.Permission.objects.filter( + all_perms = set(Permission.objects.using(using).filter( content_type__in=ctypes, ).values_list( "content_type", "codename" )) perms = [ - auth_models.Permission(codename=codename, name=name, content_type=ctype) - for c_type, (codename, name) in searched_perms - if (c_type.pk, codename) not in all_perms + Permission(codename=codename, name=name, content_type=ct) + for ct, (codename, name) in searched_perms + if (ct.pk, codename) not in all_perms ] - auth_models.Permission.objects.bulk_create(perms) + # Validate the permissions before bulk_creation to avoid cryptic + # database error when the verbose_name is longer than 50 characters + permission_name_max_length = Permission._meta.get_field('name').max_length + verbose_name_max_length = permission_name_max_length - 11 # len('Can change ') prefix + for perm in perms: + if len(perm.name) > permission_name_max_length: + raise ValidationError( + "The verbose_name of %s.%s is longer than %s characters" % ( + perm.content_type.app_label, + perm.content_type.model, + verbose_name_max_length, + ) + ) + Permission.objects.using(using).bulk_create(perms) if verbosity >= 2: for perm in perms: - logger.info("Adding permission '%s'" % perm) + print("Adding permission '%s'" % perm)