Django代理模型权限不显示



我为我的应用程序扩展了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)

我一直在管理我与South的DB。根据这篇帖子,你必须按照它指向用户的指示对它进行一些篡改。这是一个失败。我的数据库中没有太多信息,所以我取消了对South的注释,并运行了一个常规的syncdb来排除South。不幸的是,这仍然不起作用,我不知所措。感谢您的帮助。

编辑

这是在Django 1.4 上

Django 2.2中对此进行了修复,引用了发行说明:

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

和文档:

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

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

myapp | New Request | Can add new request

权限属于父模型。

myapp | engagement | Can add new request

有一个解决方法,您可以在这里看到: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))

如何使用

  • 创建目录/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

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

截至2021年和Django 3+,代理模型权限缺失的解决方案很简单,只需使用makemigrations:生成迁移即可

app@e31a3ffef22c:~/app$ python manage.py makemigrations my_app
Migrations for 'main':
  main/migrations/0193_myproxymodel.py
    - Create proxy model MyProxyModel

我来到这里,并不确定这个问题的正确原因/解决方案是什么。

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

我意识到这个问题不久前就结束了,但我正在分享对我有效的方法,以防对其他人有所帮助。

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

我要做的是解决一个已知的Django错误(https://code.djangoproject.com/ticket/11154)并且连接到CCD_ 9信号以适当地创建用于代理模型的许可。以下代码修改自https://djangosnippets.org/snippets/2677/根据那个帖子上的一些评论。

我把它放在myapp/models.py中,它保存了我的代理模型。理论上,它可以在django.contrib.contenttypes之后的任何INSTALLED_APPS中存在,因为它需要在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)

最新更新