Django - 如何使 ModelAdmin 类显示在可用权限中

发布于 2024-10-28 05:03:19 字数 1098 浏览 1 评论 0原文

我做了一个简单的 Django 应用程序。我有一个模型“访客”。我的目标是让两个两个表出现在 Django 管理中。一间包含所有访客,另一间只包含今天的访客。

我按照这些说明操作了下面的代码。然而,我的麻烦是,在管理页面中编辑组时,我无法让 VisitorExpectedTodayProxy 显示在“可用权限”中。有谁知道该怎么做?

Models.py

class Visitor(models.Model):
    visit_datetime = models.DateTimeField(null=True)
    visitor_name = models.CharField(max_length=500)

#Make dummy models for different object views in admin interface
class VisitorExpectedTodayProxy(Visitor):
    class Meta:
        proxy=True
        verbose_name = "Visitor"
        verbose_name_plural = "Today's Visitors and Regular Visitors"

更新:

我确实运行了syncdb,但我仍然没有在管理网站上看到它。同步数据库的结果:

$ python manage.py syncdb
Syncing...
No fixtures found.

Synced:
 > django.contrib.auth
 > django.contrib.contenttypes
 > django.contrib.sessions
 > django.contrib.sites
 > django.contrib.messages
 > django.contrib.admin
 > south

I made a simple Django app. I have one model "Visitor". My goal is to have two two tables appear in the Django admin. One with all of the visitors and one with only those for today.

I got everything working with the code below by following these instructions. However my trouble is I can't get VisitorExpectedTodayProxy to show up in the "available permissions" when editing groups in the admin page. Does anyone know how to do that?

Models.py

class Visitor(models.Model):
    visit_datetime = models.DateTimeField(null=True)
    visitor_name = models.CharField(max_length=500)

#Make dummy models for different object views in admin interface
class VisitorExpectedTodayProxy(Visitor):
    class Meta:
        proxy=True
        verbose_name = "Visitor"
        verbose_name_plural = "Today's Visitors and Regular Visitors"

Update:

I did run syncdb but I'm still not seeing it on the admin site. Results of syncdb:

$ python manage.py syncdb
Syncing...
No fixtures found.

Synced:
 > django.contrib.auth
 > django.contrib.contenttypes
 > django.contrib.sessions
 > django.contrib.sites
 > django.contrib.messages
 > django.contrib.admin
 > south

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

泅渡 2024-11-04 05:03:19

这是我用来手动输入代理对象的 ContentType 条目,然后为它们创建新权限的脚本。

这只是生成 sql,然后您应该在 mysql 中运行它。之后,它们应该显示在用户的权限列表中,需要将它们添加到其中。其中一些命名约定并不明显。

your_models=['proxy model',
            ]

for model in models:
    model_nospace = model.replace(' ','')
    sql = 'insert into django_content_type (name, app_label, model) values     ("%s","<<app_name>>","%s");'%(model,model_nospace)
    print sql
    for kind, permname in [('Can add','add_%s'%model_nospace),
                          ('Can change','change_%s'%model_nospace),
                          ('Can delete','delete_%s'%model_nospace),]:
        sql = 'insert into auth_permission (name, content_type_id, codename) values ("%s     %s",(select id from django_content_type where name="%s"),"%s");'%    (kind,model,model,permname)
        print sql

Here's a script I used to manually enter the ContentType entries for proxy objects, and then create new permissions for them.

This just generates the sql, which you should then run in mysql. After that they should show up in the permissions list for the user, where they'll need to be added. Some of the naming conventions for these are not obvious.

your_models=['proxy model',
            ]

for model in models:
    model_nospace = model.replace(' ','')
    sql = 'insert into django_content_type (name, app_label, model) values     ("%s","<<app_name>>","%s");'%(model,model_nospace)
    print sql
    for kind, permname in [('Can add','add_%s'%model_nospace),
                          ('Can change','change_%s'%model_nospace),
                          ('Can delete','delete_%s'%model_nospace),]:
        sql = 'insert into auth_permission (name, content_type_id, codename) values ("%s     %s",(select id from django_content_type where name="%s"),"%s");'%    (kind,model,model,permname)
        print sql
筱武穆 2024-11-04 05:03:19

我意识到这个问题不久前就被关闭了,但我正在分享对我有用的内容,以防它对其他人有帮助。

事实证明,即使我创建的代理模型的权限列在 syncdb 之后的父应用程序下,并且即使我授予非超级用户所有权限,它仍然被拒绝访问我的代理通过管理员的模型。

虽然我还没有尝试过上面基于 SQL 的修复,但修复 Django 级别的错误对我来说很有效。您必须解决已知的 Django 错误 (https://code.djangoproject.com/ticket/11154) 并连接到 post_syncdb 信号以正确创建代理模型的权限。下面的代码是根据 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)

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 after syncdb, and even though I granted my non-super user all permissions, it was still denied access to my proxy models through the admin.

Although I haven't tried the SQL based fixes above, fixing the bug at the Django level worked for me. 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)
八巷 2024-11-04 05:03:19
 ./manage.py syncdb

就是这样。它将条目添加到 auth_permission 表中。

 ./manage.py syncdb

Thats about it. It adds entries into auth_permission table.

杀手六號 2024-11-04 05:03:19

我解决这个问题的方法是删除每个表(仅删除身份验证表是不够的)。然后我从settings.py中已安装的应用程序中注释掉了south(不确定这是否导致了问题)。

然后我运行了manage.pysyncdb,现在一切正常了。

我只需要重新加载所有数据即可。我仍然不确定它一开始是怎么搞砸的。

What I did to fix this is I dropped every table (deleting just the auth tables wasn't enough). Then I commented out south from the installed apps in settings.py (not sure if that was causing problems).

Then I ran manage.py syncdb and everything is working now.

I just have to reload all of my data. I'm still not sure how it got messed up in the first place.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文