Django代理模型权限不会出现

问题描述 投票:9回答:6

我为我的应用程序扩展了Django管理站点,允许非员工/超级用户访问。这工作得很好。

我为现有模型创建了一个代理模型,并将其注册到我的管理站点,但是,对于非员工用户,它不会出现。从我阅读的文档中,我的理解是代理模型获得了自己的权限。我检查过,这些没有出现在可用权限列表中。

这是我的代码,以防它有用:

正常模型

class Engagement(models.Model):
    eng_type = models.CharField(max_length=5)
    environment = models.CharField(max_length=8)    
    is_scoped = models.BooleanField()    

    class Meta:
        ordering = ['eng_type', 'environment']
        app_label = 'myapp'

代理模型

class NewRequests(Engagement):
    class Meta:
        proxy = True
        app_label = 'myapp'
        verbose_name = 'New Request'
        verbose_name_plural = 'New Requests'

模特管理员

class NewRequestsAdmin(ModelAdmin):
pass

def queryset(self, request):
    return self.model.objects.filter(is_scoped=0)

自定义管理员注册

myapps_admin_site.register(NewRequests, NewRequestsAdmin)

我一直在和南方管理我的数据库。根据this post,你必须跟随the instructions it points users to篡改它。这是一次失败。我的数据库中没有很多信息,因此我取消注释南并运行常规syncdb以排除South。不幸的是,这仍然没有用,我不知所措。任何帮助表示赞赏。

编辑

这是在Django 1.4上

django django-models python-2.7 django-admin django-south
6个回答
7
投票

事实证明我没有做错任何事。我正在寻找权限

myapp | New Request | Can add new request

权限属于父模型。

myapp | engagement | Can add new request


4
投票

有一个解决方法,你可以在这里看到:https://gist.github.com/magopian/7543724

它可以根据你的django版本而有所不同,但原理是一样的。

用Django 1.10.1测试

# -*- coding: utf-8 -*-

"""Add permissions for proxy model.
This is needed because of the bug https://code.djangoproject.com/ticket/11154
in Django (as of 1.6, it's not fixed).
When a permission is created for a proxy model, it actually creates if for it's
base model app_label (eg: for "article" instead of "about", for the About proxy
model).
What we need, however, is that the permission be created for the proxy model
itself, in order to have the proper entries displayed in the admin.
"""

from __future__ import unicode_literals, absolute_import, division

import sys

from django.contrib.auth.management import _get_all_permissions
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand
from django.apps import apps
from django.utils.encoding import smart_text

class Command(BaseCommand):
    help = "Fix permissions for proxy models."

    def handle(self, *args, **options):
        for model in apps.get_models():
            opts = model._meta
            ctype, created = ContentType.objects.get_or_create(
                app_label=opts.app_label,
                model=opts.object_name.lower(),
                defaults={'name': smart_text(opts.verbose_name_raw)})

            for codename, name in _get_all_permissions(opts):
                p, created = Permission.objects.get_or_create(
                    codename=codename,
                    content_type=ctype,
                    defaults={'name': name})
                if created:
                    sys.stdout.write('Adding permission {}\n'.format(p))

How to use

  • 创建一个目录/myproject/myapp/management/commands
  • 创建文件/myproject/myapp/management/__init__.py
  • 创建文件/myproject/myapp/management/commands/__init__.py
  • 将上面的代码保存到/myproject/myapp/management/commands/fix_permissions.py
  • 运行/manage.py fix_permissions

3
投票

这是Django中的一个已知错误:https://code.djangoproject.com/ticket/11154(检查一些补丁的评论)


3
投票

这在Django 2.2中修正,引用release notes

现在使用代理模型的内容类型而不是具体模型的内容类型创建代理模型的权限。迁移将在您运行迁移时更新现有权限。

docs

代理模型的工作方式与具体模型完全相同。权限是使用代理模型的自己的内容类型创建的。代理模型不会继承它们子类的具体模型的权限。


0
投票

我意识到这个问题前一段时间已经结束了,但我正在分享对我有用的东西,以防它可以帮助别人。

事实证明,即使我创建的代理模型的权限列在父应用程序下(如@chirinosky)所提到的,即使我授予我的非超级用户所有权限,它仍然被拒绝访问我的代理模型通过管理员。

我必须做的是解决已知的Django bug(https://code.djangoproject.com/ticket/11154)并连接到post_syncdb信号以正确创建代理模型的权限。根据该主题的一些注释,下面的代码是根据https://djangosnippets.org/snippets/2677/修改的。

我把它放在myapp / models.py中,它包含我的代理模型。从理论上说,这可以存在于INSTALLED_APPS之后的任何django.contrib.contenttypes中,因为它需要在update_contenttypes处理程序注册post_syncdb信号后加载,以便我们可以断开它。

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
投票

对于Django 1.11由于auth_permission表中的content_type_id错误,此问题是相关的。默认情况下,它会添加基本模型的内容类型,而不是代理模型内容类型。

© www.soinside.com 2019 - 2024. All rights reserved.