python - ModelAdmin 线程安全/缓存问题

标签 python django django-admin django-permissions

最终,我的目标是扩展 Django 的 ModelAdmin 以提供字段级权限——也就是说,给定请求对象的属性和正在编辑的对象的字段值,我想控制字段/内联对用户可见。我最终通过向 ModelAdmin 添加 can_view_field() 方法并将内置的 get_form()get_fieldset() 方法修改为删除/排除用户无权查看的字段+内联(由 can_view_field() 确定)。如果你想看代码,我把它放在了 in a pastebin ,因为它很长而且只是有点相关。

效果很好……差不多。我似乎遇到了某种线程安全或缓存问题,其中 ModelAdmin 对象的状态以可重现的方式从一个请求泄漏到另一个请求。

我将用一个简单的例子来说明这个问题。假设我有一个模型,我已经使用字段级权限代码扩展了它的 ModelAdmin。该模型有两个字段: - public_field,任何工作人员都可以看到/编辑 - secret_field,只有 super 用户才能看到/编辑

在这种情况下,can_view_field() 方法将如下所示:

def can_view_field(self, request, obj, field_name):
    """
    Returns boolean indicating whether the user has necessary permissions to
    view the passed field.
    """
    if obj is None:
        return request.user.has_perm('%s.%s_%s' % (
            self.opts.app_label,
            action,
            obj.__class__.__name__.lower()
        ))
    else:
        if field_name == "public_field":
            return True
        if field_name == "secret_field" and request.is_superuser:
            return True
        return False

测试用例 1:重新启动服务器,如果您首先以 super 用户身份查看更改列表表单,您会看到应该出现的表单,同时包含 public_fieldsecret_field 可见。如果您注销并以工作人员(但不是 super 用户)的身份查看它,您只会看到 public_field

测试用例 2:在重新启动服务器的情况下,如果您首先以工作人员身份登录,您仍然只能看到 public_field。但是,如果您随后注销并以 super 用户身份查看,您不会看到 secret_field。这是 100% 可重现的。

我已经完成了一些基本的线程安全诊断:

  1. get_form() 的末尾,我打印出了 ModelForm 对象的内存地址。正如它应该的那样,它对于每个请求都是唯一的。因此,ModelForm 对象不是问题。
  2. 在管理员注册之前,我尝试打印 ModelAdmin 对象的内存地址。在测试用例 1 中,它对于两个请求都是唯一的。然而,对于测试用例 2,它在第二次请求时根本不打印。

此时,我是一头雾水。我的下一个研究点将是管理员注册系统(我承认对此一无所知)。状态随着服务器重启而重置,所以似乎必须缓存 ModelAdmin?还是线程安全问题?如果我把它变成一个工厂并返回一个 ModelAdmin 的 deepcopy(),它会为每个请求提供一个新的 ModelAdmin 吗?我一无所知,将不胜感激任何想法。谢谢!

最佳答案

我很困惑为什么您认为 ModelAdmin 应该是每个请求的新实例。 admin 对象由每个 admin.py 中的 admin.site.register(Model) 调用实例化,后者又从 url 中的 admin.autodiscover() 调用。 py。换句话说,这发生在进程启动时。考虑到大多数 Web 服务环境的动态多进程性质,您可能会或可能不会获得任何特定请求的新进程 - 当然您不会每次都获得一个。

因此,在像 ModelAdmin 这样的全局对象上存储或更改状态是不明智的。我没有正确查看您的链接代码,但至少有一种情况是您由于方法调用而更改了 self 上的属性。不要那样做 - 您需要找到其他方法在方法之间传递动态值。

关于python - ModelAdmin 线程安全/缓存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3388111/

相关文章:

python - 如果其他功能在 Pandas 数据框中

python - 使用 Django,为什么 REMOTE_ADDR 会在 Web 服务器上返回 127.0.0.1?

python - Django,用户友好的方式来在管理员的 filter_horizo​​ntal 小部件中订购对象

python - 如何使用 django admin 在数据库中插入记录后添加函数?

Django-tastypie 创建 URL 层次结构

Django admin - 更改权限列表

python - 在valueError循环中中断导致错误

Python SQLAlchemy 和 Postgres - 如何使用 json 值中的子字符串进行搜索

python - 如何删除二叉搜索树的所有节点

python - Python 中的文件校验和