如何在 Django admin 中实现全局隐式过滤器?

Dan*_*air 6 django admin filter permanent

我的很多模型都有一个“公司”模型的外键。每个登录的用户都可以是一个或多个公司的一部分(用户 m2m 公司,不为空)。

我希望当前的管理员用户有“公司护目镜”,即选择列表,在管理员索引页面或基本标题上,他们可以在其中切换他们的“当前”公司。这样做应该会自动应用“公司等于”过滤器 - 对于具有公司外键的模型 - 除了任何其他过滤器。

实现这一目标的最佳方法是什么?

注意:这是管理界面的舒适功能,现阶段不需要对模型进行实际保护(客户端视图确实需要,但我可以使用自定义管理器并通过 request.user 在那里查找)。

我现在的想法是:

  1. 在会话中存储当前公司。

  2. 使用中间件从会话中查找当前公司,并将公司附加到所有相关链接:

    a) change_list: (?/&)"company__eq=42"

    b) change_view "add?company=42" 对于具有 Company 外键的模型。

    这可能需要反向或模式匹配 URL 以找出它们的模型并检查它是否存在外键(或者我可能会事先准备该列表以提高性能)。

  3. 在每个 ModelAdmin 表单中包含外键字段,但通过 CSS 隐藏它,以便 change_view add ("new") 包含来自链接的预设外键值而不提及它。

您认为这是一种可行的方法吗?

如果实现了http://code.djangoproject.com/ticket/10761,我想我可以指定一个自定义查询集,它从 request.session 读取当前公司并完成它。也许更好地快速跟踪(=制作并提交补丁)该票?

编辑:或者可能只是在每个需要它/具有外键的 ModelAdmin 上重新定义 queryset() 方法?

Yuj*_*ita 4

我的投票是压倒一切ModelAdmin.queryset,因为您可以方便地访问那里的请求。覆盖save_model第 3 点。

 class MyModelAdmin(admin.ModelAdmin):
    def queryset(self, request):
        qs = super(MyModelAdmin, self).queryset(request)
        if request.session.get('company_goggles'):
             return qs.filter(company=request.session['company_goggles'])
        return qs
Run Code Online (Sandbox Code Playgroud)

如果您有很多模型,我会将其子类化ModelAdminGogglesAdmin定义一个字段/默认值以从中提取字段名称以及公司的预保存自动注入。

class CompanyGogglesAdmin(admin.ModelAdmin):
    def queryset(self, request):
        qs = super(CompanyGoggleAdmin, self).queryset(request)
        if request.session.get('company_goggles'):
            return qs.filter(**{ getattr(self, 'company_field', 'company') : 
                          request.session['company_goggles'] })
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我真的很喜欢“公司护目镜”这个术语。