【问题标题】:How can I implement a global, implicit filter in Django admin?如何在 Django admin 中实现全局隐式过滤器?
【发布时间】:2011-03-17 20:02:09
【问题描述】:

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

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

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

注意:这意味着作为管理界面的舒适功能,在此阶段不需要对模型进行实际保护(客户端视图确实需要,但我可以使用自定义管理器并通过 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() 方法?

【问题讨论】:

    标签: django filter admin permanent


    【解决方案1】:

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

     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
    

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

    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'] })
    

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

    【讨论】:

    • 谢谢。几乎与 lazerscience 的答案相同,另外感谢您提供基类和字段名称参数的想法。我想我现在已经准备好了。回到编码。 :-)
    • 注意:应该是“request.session.get('company_goggles', None)”,而不是 getattr() - request.session 类似于字典。
    • 谢谢丹尼,我不知道我在想什么。那种意识流风格的编码!
    • queryset 方法现在称为get_queryset
    【解决方案2】:

    回答最后一个问题:如果您只想显示查询集中的某些项目,您可以毫无问题地覆盖ModelAdminqueryset() 方法。例如,如果您要在当前会话中设置公司。您还可以覆盖save_model() 方法,让company ForeignKey 在保存表单时始终指向用户的公司:

    class MyAdmin(admin.ModelAdmin):
        def queryset(self, request):
            company = request.session.get('company', None)
            qs = self.model._default_manager.get_query_set()
            if not company is None:
                qs = qs.filter(company=company)
            return qs
    
        def save_model(self, request, obj, form, change):
            company = request.session.get('company', None):
            instance = form.save(commit=False)
            if not change or not instance.company:
                instance.company = company
            instance.save()
            form.save_m2m()
            return instance
    

    【讨论】:

    • 啊,当然是 save_model()!谢谢,我想现在所有的方框都打勾了。 :-)
    • 如果你有很多类(并且懒得去寻找它们的基类),你如何全局为项目中的所有表单注册它?
    猜你喜欢
    • 2019-06-11
    • 2014-01-30
    • 2011-09-10
    • 2010-09-15
    • 2021-08-31
    • 1970-01-01
    • 2018-03-01
    • 2016-08-02
    • 1970-01-01
    相关资源
    最近更新 更多