使用 SelectMultiple 渲染的 Django ArrayField 不将所选选项显示为“已选择”

Dev*_*eer 2 python django django-models django-forms

我正在尝试使用这样的 SelectMultiple 小部件渲染 postgres Arrayfield 值

在 models.py 中:

SLOT_CHOICES = (('A','Slot A'),('B','Slot B'),('C','Slot C'),('D','Slot D'),('E','Slot E'),('F','Slot F'),('G','Slot G'),('H','Slot H'),('P','Slot P'),('Q','Slot Q'),('R','Slot R'),('S','Slot S'),('T','Slot T'),)
core_slots = ArrayField(models.CharField(max_length=1,choices=SLOT_CHOICES),blank=True,null=True)
Run Code Online (Sandbox Code Playgroud)

在forms.py中:

    self.fields['core_slots'].widget = forms.SelectMultiple(attrs={
            'placeholder': 'Choose slots',
            'class': 'multi-select-input',
        },choices=self.Meta.model.SLOT_CHOICES)
Run Code Online (Sandbox Code Playgroud)

如果我选择一个选项并提交,然后尝试使用“实例”获取填写的表单,那么它可以正常工作并将先前选择的选项显示为“已选择”。但是,如果我选择多个选项,那么在提交时,所有选定的值都会正确插入到数据库中,但如果我尝试使用“实例”获取填写的表单,那么它不会显示任何选定的选项。

对于 ManyToManyField 不会出现此问题。

在 models.py 中:

past_courses = models.ManyToManyField(Course,blank=True)
Run Code Online (Sandbox Code Playgroud)

在forms.py中:

    self.fields['past_courses'].queryset = Course.objects.filter(~Q(dept=self.instance.dept)).order_by('name')
    self.fields['past_courses'].widget.attrs.update({
            'placeholder': 'Choose past courses',
            'class': 'multi-select-input',
        })
Run Code Online (Sandbox Code Playgroud)

这个效果很好。只有使用 SelectMultiple 小部件渲染的 ArrayField 存在问题。我想在模板中显示提交的选项,有什么方法可以解决此问题,或者是否有其他方法可以在模板中显示选定的选项。

小智 5

我发现这似乎是一个问题,因为 SelectMultiple 小部件使用 ChoiceWidget,它有一个 format_value 方法,无法正确处理多个选择。至少 Django 1.11 是这样。format_value 执行以下操作:

def format_value(self, value):
    """Return selected values as a list."""
    if value is None and self.allow_multiple_selected:
        return []
    if not isinstance(value, (tuple, list)):
        value = [value]
    return [force_text(v) if v is not None else '' for v in value]
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它应该以列表的形式返回选定的值。但是如果它不是元组或列表,则运行的代码是错误的。它本质上只是使值中的项目成为列表中的单个条目。因此,当您选择了多个项目(例如“A”、“B”和“C”)时,它们将通过此 format_value 函数作为“A、B、C”,而这实际上只是使其成为 ['A,B, C'] - 这是错误的。它需要是['A','B','C']。所以我只是输入代码来重写这个函数,如下所示:

def format_value(self, value):
    """Return selected values as a list."""
    if value is None and self.allow_multiple_selected:
        return []
    if not isinstance(value, (tuple, list)):
        # This means it should be a comma delimited list of items so parse it
        value = value.split(',')

    return [force_text(v) if v is not None else '' for v in value]
Run Code Online (Sandbox Code Playgroud)

现在看来这对我来说效果很好。我在 Django 1.11 上测试了选择单个项目、多个项目、无项目以及正确保存到数据库的所有内容,并且也很好地显示在 Django 管理中。希望这可以帮助。