替换表单的默认多对多小部件

Posted

技术标签:

【中文标题】替换表单的默认多对多小部件【英文标题】:Replacement for the default ManyToMany Widget of Forms 【发布时间】:2016-07-29 11:36:12 【问题描述】:

我知道在 django 管理界面中替换 ManyToMany Widget:

class SomeModelAdmin(admin.ModelAdmin):
    filter_horizontal = ('users',)

但是如何替换所有视图中的默认小部件?

我想这可以在不更改我的代码或 django 中的一行的情况下实现。

如果我能在这张带有小部件的图片中添加类似作者部分(用于多对多输入的两个框)之类的东西,那就太好了:

我可以使用 ctrl + 点击,但我的用户不能。他们想要一种更简单的方法。

有没有一种方法可以替换所有多选小部件而无需对我的代码进行很多更改?

【问题讨论】:

覆盖 MultipleSelect 小部件类。 @AvinashRaj 请详细说明“覆盖 MultipleSelect 小部件类。” 【参考方案1】:

您可以使用覆盖 formfield_for_manytomany 的基类

from django.contrib.admin import widgets

class ManyToManyAdmin(admin.ModelAdmin):
    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        kwargs['widget']= widgets.FilteredSelectMultiple(
            db_field.verbose_name,
            db_field.name in self.filter_vertical
        )

        return super(admin.ModelAdmin, self).formfield_for_manytomany(
            db_field, request=request, **kwargs)

class SomeModelAdmin(ManyToManyAdmin):
    pass

【讨论】:

【参考方案2】:

如果我不明白您的问题,请在 cmets 中澄清。

Django Form Widgets Documentation 提供了几个预制小部件,您可以使用它们来指定如何呈现表单中的字段。

无需修改视图中的代码,我可以简单地将 widget 关键字 arg 添加到相应的表单字段中。

forms.py (v1)

class TestForm(forms.Form):
    CHOICES = (
    (1, "choice1"),
    (2, "choice2"),
    (3, "choice3"),
    )
    field = forms.ChoiceField(choices=CHOICES)

这呈现为下拉列表select

<select id="id_field" name="field">
  <option value="1">choice1</option>
  <option value="2">choice2</option>
  <option value="3">choice3</option>
</select>

现在将 widget 关键字 arg 添加到我的字段中:

forms.py (v2)

field = forms.ChoiceField(choices=CHOICES, widget=forms.CheckboxSelectMultiple)

这呈现为复选框列表:

<ul id="id_field">
<li>
  <label for="id_field_0"><input id="id_field_0" name="field" type="checkbox" value="1" /> choice1</label>
</li>
<li>
  <label for="id_field_1"><input id="id_field_1" name="field" type="checkbox" value="2" /> choice2</label>
</li>
<li>
  <label for="id_field_2"><input id="id_field_2" name="field" type="checkbox" value="3" /> choice3</label>
</li>
</ul>

编辑

还可以添加 Django Admin 使用的小部件。有关这方面的更多信息,请参阅Django multi-select widget?。只需导入适当的小部件:

from django.contrib.admin.widgets import FilteredSelectMultiple

并改用它。请注意,在这种特殊情况下,您还需要包含表单的 media 才能获得所需的效果。

【讨论】:

是的,CheckboxSelectMultiple 比默认小部件的 ctrl-click 好用得多。有没有办法让管理员中的两个漂亮的框以小部件的方式左右移动条目?我在问题中添加了一张图片。 @guettli 您可以在顶部添加一些 css 和 js,以使其更好,例如 github.com/lou/multi-select @guettli 你对这个答案有后续的问题吗?【参考方案3】:

您需要替换 django 表单中的默认小部件。

这对我有用:

    from django import forms
    from django.contrib.admin.widgets import FilteredSelectMultiple
    # replace MultipleChoise in Forms
    forms.MultipleChoiceField.widget = FilteredSelectMultiple("verbose name", is_stacked=False)
    # replace MultipleChoise in ModelForms
    forms.ModelMultipleChoiceField.widget = FilteredSelectMultiple("verbose name", is_stacked=False)
    将上面的代码添加到主项目中的文件forms_setup.py

    然后在settings.py导入文件forms_setup.py

    from .forms_setup import *
    

【讨论】:

在模块级别覆盖......我认为它被称为猴子补丁......是的,如果你幸运的话,这可能会起作用。在这些行之前执行的代码无法通过此修补程序...

以上是关于替换表单的默认多对多小部件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用多对多字段填充默认表单数据?

如何在 WinForms 中绑定多对多关系?

Django admin - 如何在自定义管理表单中为多对多字段添加绿色加号

具有多对多关系的Django表单不保存

通过 Django 中的模型表单保存多对多数据

Qt-信号和槽-多对多