User permissions on proxy models in modeladmin

前端 未结 4 1236
被撕碎了的回忆
被撕碎了的回忆 2020-12-17 21:22

When using a proxy model:

class Uf(models.Model):
...

class CustomUf(Uf):
    class Meta:
        proxy = True

class CustomUfAdmin(admin.ModelAdmin)

admin         


        
相关标签:
4条回答
  • 2020-12-17 21:41

    You need to run syncdb again so the new content types can be picked up.

    0 讨论(0)
  • 2020-12-17 21:56

    Ok, Chris remark about content types gave me the hint...

    I made the mistake to define the proxy object in "admin.py". This way, you have to be superadmin to access it.

    If I define the proxy object in models.py, then the content type appears and everything works fine...

    0 讨论(0)
  • 2020-12-17 21:59

    I realize this question was closed a while ago, but I'm sharing what worked for me in case it might help others.

    It turns out that even though permissions for the proxy models I created were listed under the parent apps, and even though I granted my non-super user all permissions, it was still denied access to my proxy models through the admin.

    If you want to avoid raw SQL and script the fix in Python, you have to workaround a known Django bug (https://code.djangoproject.com/ticket/11154) and connect to the post_syncdb signal to properly create permissions for the proxy models. The code below is modified from https://djangosnippets.org/snippets/2677/ per some of the comments on that thread.

    I placed this in myapp/models.py that held my proxy models. Theoretically this can live in any of your INSTALLED_APPS after django.contrib.contenttypes because it needs to be loaded after the update_contenttypes handler is registered for the post_syncdb signal so we can disconnect it.

    def create_proxy_permissions(app, created_models, verbosity, **kwargs):
        """
        Creates permissions for proxy models which are not created automatically
        by 'django.contrib.auth.management.create_permissions'.
        See https://code.djangoproject.com/ticket/11154
        Source: https://djangosnippets.org/snippets/2677/
    
        Since we can't rely on 'get_for_model' we must fallback to
        'get_by_natural_key'. However, this method doesn't automatically create
        missing 'ContentType' so we must ensure all the models' 'ContentType's are
        created before running this method. We do so by un-registering the
        'update_contenttypes' 'post_syncdb' signal and calling it in here just
        before doing everything.
        """
        update_contenttypes(app, created_models, verbosity, **kwargs)
        app_models = models.get_models(app)
        # The permissions we're looking for as (content_type, (codename, name))
        searched_perms = list()
        # The codenames and ctypes that should exist.
        ctypes = set()
        for model in app_models:
            opts = model._meta
            if opts.proxy:
                # Can't use 'get_for_model' here since it doesn't return
                # the correct 'ContentType' for proxy models.
                # See https://code.djangoproject.com/ticket/17648
                app_label, model = opts.app_label, opts.object_name.lower()
                ctype = ContentType.objects.get_by_natural_key(app_label, model)
                ctypes.add(ctype)
                for perm in _get_all_permissions(opts, ctype):
                    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(Permission.objects.filter(
            content_type__in=ctypes,
        ).values_list(
            "content_type", "codename"
        ))
    
        objs = [
            Permission(codename=codename, name=name, content_type=ctype)
            for ctype, (codename, name) in searched_perms
            if (ctype.pk, codename) not in all_perms
        ]
        Permission.objects.bulk_create(objs)
        if verbosity >= 2:
            for obj in objs:
                sys.stdout.write("Adding permission '%s'" % obj)
    
    
    models.signals.post_syncdb.connect(create_proxy_permissions)
    # See 'create_proxy_permissions' docstring to understand why we un-register
    # this signal handler.
    models.signals.post_syncdb.disconnect(update_contenttypes)
    
    0 讨论(0)
  • 2020-12-17 22:03

    Please see this related Django issue: #11154

    You can overcome this by manually adding the rows to the 'auth_permission' table like:

    INSERT INTO "auth_permission" ("name","content_type_id","codename") 
        VALUES ('Can add proxy model name',{content_type_id},'add_proxy_model_name');
    

    Where content type id is the integer id of the relavent content type.

    0 讨论(0)
提交回复
热议问题