Django admin - 模型对超级用户可见,而不是员工用户
Posted
技术标签:
【中文标题】Django admin - 模型对超级用户可见,而不是员工用户【英文标题】:Django admin - model visible to superuser, not staff user 【发布时间】:2018-02-02 03:30:38 【问题描述】:我知道syncdb
和makemigrations
,但我们只能在生产环境中这样做。
我们最近在生产环境中创建了几个表。正如预期的那样,任何用户在管理员上都看不到表格。
发布后,我们在生产 sql 上手动执行了以下 2 个查询(我在本地运行迁移并执行 show create table
查询以获取原始 sql)
django_content_type
INSERT INTO django_content_type(name, app_label, model)
values ('linked_urls',"urls", 'linked_urls');
auth_permission
INSERT INTO auth_permission (name, content_type_id, codename)
values
('Can add linked_urls Table', (SELECT id FROM django_content_type where model='linked_urls' limit 1) ,'add_linked_urls'),
('Can change linked_urls Table', (SELECT id FROM django_content_type where model='linked_urls' limit 1) ,'change_linked_urls'),
('Can delete linked_urls Table', (SELECT id FROM django_content_type where model='linked_urls' limit 1) ,'delete_linked_urls');
现在这个模型在超级用户下是可见的,并且可以授予员工用户访问权限,但是员工用户看不到它。 里面有没有需要输入的表项?
或者在没有syncdb、迁移的情况下有没有其他方法可以解决这个问题?
【问题讨论】:
可能有一个 staff 用户组。你授予它权限了吗? 是的,还有很多不属于任何组的独立员工用户! 那么我建议创建用户组staff
并将其分配给所有员工用户。我不喜欢那个,但也应该可以通过一个 SQL 命令来处理分配。
刚刚尝试过,创建了一个组,将模型访问权限授予该组...将其分配给用户。仍然没有运气。看不到表格。
【参考方案1】:
我们最近在生产环境中创建了几个表。
我可以通过两种方式阅读您在那里写的内容。
第一种方式:您使用 SQL 语句创建了表,在 Django 中没有相应的模型。如果是这样的话,再多的修改内容类型和权限都会让 Django 突然使用这些表。您需要为表创建模型。也许他们会是unmanaged,但他们需要存在。
第二种方式:Django中对应的模型确实存在,你只是为它们手动创建了表,所以这不是问题。在这种情况下我要做的是运行以下代码,代码后有解释:
from django.contrib.contenttypes.management import update_contenttypes
from django.apps import apps as configured_apps
from django.contrib.auth.management import create_permissions
for app in configured_apps.get_app_configs():
update_contenttypes(app, interactive=True, verbosity=0)
for app in configured_apps.get_app_configs():
create_permissions(app, verbosity=0)
上面的代码实际上是执行 Django 在运行迁移之后执行的工作。当迁移发生时,Django 只是根据需要创建表,然后当它完成时,它调用update_contenttypes
,它会扫描与项目中定义的模型关联的表并将需要添加的任何内容添加到django_content_type
表中。然后它调用create_permissions
来更新auth_permissions
需要添加的添加/更改/删除权限。我使用上面的代码来强制尽早创建权限during a migration。例如,如果我有一个数据迁移,它会创建需要引用新权限的组。
【讨论】:
这是您提到的第二种方式。现在,我的问题是我无法在 prod / pre-prod 上的 shell 上运行东西。有没有我可以通过的原始sql
东西让 DBA 执行查询并完成工作?
你没有这个问题。任何 Django 管理命令都可以通过从 python 代码中调用django.core.management.call_command
来运行。如果您创建一个包装该功能的视图,您可以运行任何您想要的东西。但是,如果有疑问,您也可以使用 subprocess 库从 python 和 Django 视图中调用命令。是的,这两种方式都可以让你运行迁移。【参考方案2】:
所以,我终于有了一个解决方案。我在 django 上做了很多调试,并且显然在函数下面(django.contrib.auth.backends
)完成了提供权限的工作。
def _get_permissions(self, user_obj, obj, from_name):
"""
Returns the permissions of `user_obj` from `from_name`. `from_name` can
be either "group" or "user" to return permissions from
`_get_group_permissions` or `_get_user_permissions` respectively.
"""
if not user_obj.is_active or user_obj.is_anonymous() or obj is not None:
return set()
perm_cache_name = '_%s_perm_cache' % from_name
if not hasattr(user_obj, perm_cache_name):
if user_obj.is_superuser:
perms = Permission.objects.all()
else:
perms = getattr(self, '_get_%s_permissions' % from_name)(user_obj)
perms = perms.values_list('content_type__app_label', 'codename').order_by()
setattr(user_obj, perm_cache_name, set("%s.%s" % (ct, name) for ct, name in perms))
return getattr(user_obj, perm_cache_name)
那么问题出在哪里?
问题在于这个查询:
INSERT INTO django_content_type(name, app_label, model)
values ('linked_urls',"urls", 'linked_urls');
最初看起来不错,但实际执行的查询是:
--# notice the caps case here - it looked so trivial, i didn't even bothered to look into it untill i realised what was happening internally
INSERT INTO django_content_type(name, app_label, model)
values ('Linked_Urls',"urls", 'Linked_Urls');
所以 django 在内部执行 migrate
时,确保所有内容都以 小写 迁移 - 这就是问题!!
我执行了一个单独的查询来小写所有以前的插入和瞧!
【讨论】:
以上是关于Django admin - 模型对超级用户可见,而不是员工用户的主要内容,如果未能解决你的问题,请参考以下文章
除超级用户外,如何使字段只在django admin中读取?