【问题标题】:dynamic manipulation of django admin formdjango管理表单的动态操作
【发布时间】:2012-02-17 15:27:22
【问题描述】:

我有一个修改后的管理表单,我在其中添加了一个字段,该字段将修改当前模型的父对象的值。现在,根据用户,我需要

  • 更改该额外字段的查询集
  • 将另一个字段设置为只读(或者更好,甚至完全隐藏)

基本上,我下面的代码可以按我的预期工作。超级用户获取整个查询集,而另一个字段是 not 只读的。所有其他用户都获得有限的查询集,而其他字段 是只读的。但是,一旦我在不同的浏览器中以非超级用户身份打开该站点,即使是超级用户也会得到与非超级用户相同的结果。似乎 django 以某种方式缓存了结果?如果我在条件分支中放置一些打印语句,它们会被正确打印。因此,该方法每次仍会被调用,并且似乎仍在执行这些步骤。只有错误的结果。

这是缓存问题吗?我做错了什么吗?会不会是django测试服务器的bug?

def get_form(self, request, obj=None, **kwargs):
    form = super(MultishopProductAdmin, self).get_form(request, obj, **kwargs)
    if obj is not None:
        form.declared_fields['categories'].initial = obj.product.category.all()
    if not request.user.is_superuser:
        user_site = request.user.get_profile().site
        form.declared_fields['categories'].queryset = Category.objects.filter(site__id=user_site.id)
        self.readonly_fields = ('virtual_sites', )
        if obj is not None:
            form.declared_fields['categories'].initial = obj.product.category.filter(site__id=user_site.id)
    return form

【问题讨论】:

    标签: django admin customization


    【解决方案1】:

    是的,你做错了。在 Django 1.2+ 中,您可以使用 get_readonly_fields

    来自this answer

    ModelAdmin 仅针对它收到的所有请求实例化一次。因此,当您像这样定义只读字段时,您就是在永久设置它。

    关于更改queryset。来自文档:

    class MyModelAdmin(admin.ModelAdmin):
        def queryset(self, request):
            qs = super(MyModelAdmin, self).queryset(request)
            if request.user.is_superuser:
                return qs
            return qs.filter(author=request.user)
    

    【讨论】:

    • 谢谢,这已经解决了我的只读字段问题。 queryset 方法不是我想要的。我通常会在类别属性上使用formfield_for_manytomany。但是,由于这不是模型的一部分,因此不会为该字段调用 formfield_for_manytomany。那么我可以限制它的查询集的任何其他方法吗?
    • 当然,还要为它传递初始数据。我实际上希望这很简单,但是除了通常的 initial= 参数之外我找不到任何东西,但这并不能满足我的需要。
    • 您要过滤什么,为什么?
    • 模型 A(该代码摘录的用途)类似于模型 B 的“代理”。它不是子类,但模型 A 需要更新模型 B 的类别 M2M 字段。这一切都有效这样很好,但为了更容易使用,我需要限制类别的选择。另外,我需要让它通过初始数据反映当前的选择,具体取决于用户(所以我需要请求)。
    • 那你需要formfield_for_foreignkey
    【解决方案2】:

    扩展 dan-klasson 的答案:永远不要在任何 ModelAdmin 方法(如 self.readonly_fields)中设置实例属性,以防止出现您所描述的问题。仅使用 Django ModelAdmin 的选项(类级别)或方法来操作任何行为。关于只读字段,您可以使用具有此签名的ModelAdmin.get_readonly_fields 方法:get_readonly_fields(self, request, obj=None)

    【讨论】:

      【解决方案3】:

      所以我找不到一个非常聪明的方法来使用 django admin 的自定义方法来做我想做的事情。我现在最终做的是实现管理员的change_view,手动设置我自己的表单并从那里执行我所有的自定义初始化。

      然后我通过设置change_form_template 提供了一个自定义模板,它只是扩展admin/change_form.html,但呈现我自己的表单而不是默认表单。我还设置了extra_context['adminform'] = None,以便删除默认的管理表单。

      这样我现在可以按照我需要的方式自定义我的表单,但仍然可以使用所有其他管理便利。到目前为止,它似乎工作得很好。我认为也不是最优雅的解决方案,但我能想到的最好的解决方案。

      【讨论】:

        猜你喜欢
        • 2020-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-18
        • 1970-01-01
        • 1970-01-01
        • 2021-08-03
        • 1970-01-01
        相关资源
        最近更新 更多