Django,如何从modelform的choicefield中删除空白选项?

35

我创建了一个带有外键的模型:

class Book(models.Model):
    library = models.ForeignKey(Library, null=False, blank=False)
    ...

然后我使用ModelForm创建了一个表单,以供用户查看:

class BookSubmitForm(ModelForm):
    class Meta:
        model = Book

当我展示这个表单页面时,我可以看到库的选项,但也会有一个空白选项(--------)出现,默认情况下是这样的。

我认为在模型中加入null=False和blank=False可以消除ModelForm中的空白选项,但事实并非如此。我该怎么做才能只显示实际选项而不显示空白选项呢?

6个回答

49

请参考ModelChoiceField。您需要将empty_label设置为None。因此,您的代码应该像这样:

class BookSubmitForm(ModelForm):
    library = ModelChoiceField(queryset=Library.objects, empty_label=None)

    class Meta:
        model = Book    

编辑:将字段名更改为小写


它有点起作用,但我仍然在表单中看到原始的ChoiceField,其中包含空白选项和新的ChoiceField,标签和选择相同,但没有空白选项。看起来这种方法不是覆盖表单,而是使用相同的字段扩展它。 - Bastian
好的,我的错,这是一个打字错误,我使用了大写字母作为你的例子中的“Library”的首字母。当切换为小写的“library”时,它实际上覆盖了该字段。谢谢! - Bastian
2
太好了!如果您不打算更改查询集,您还可以简单地使用self.fields['library'].empty_label = None - gdvalderrama

15

self.fields['xxx'].empty_label = None如果你的字段类型是TypedChoiceField,则不起作用,因为它没有empty_label属性。

我们应该做的是删除第一个选项:

class BookSubmitForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(BookSubmitForm, self).__init__(*args, **kwargs)

        for field_name in self.fields:
            field = self.fields.get(field_name)
            if field and isinstance(field , forms.TypedChoiceField):
                field.choices = field.choices[1:]

仅在您无法为模型中的字段设置默认值时使用此选项,这是一种更清洁的选择(参见Daniel Sokolowski的答案)。 - gengkev

12

如果您使用ModelForm,则不必指定queryset、required、label等内容。但是对于获得投票的答案,您需要再次执行此操作。

实际上,您可以这样做以避免重新指定所有内容

class BookSubmitForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(BookSubmitForm, self).__init__(*args, **kwargs)
        self.fields['library'].empty_label = None

    class Meta:
        model = Book 

3
对我来说这种方法似乎不起作用。如果像上面那样将 empty_label 设置为空,我仍然会看到“---------”作为选项之一。这在 Django 1.10 版本中是否仍然有效? - Anupam
实际上,我发现它是一个TypedChoiceField,因此下面@Mithril的答案有效。 - Anupam

12
如果在模型字段定义中指定blank=Falsedefault=<VALUE>,则Django默认不会呈现空白选项;请注意,默认值可以是无效选择,并设置为''或任何无效选择
class Book(models.Model):
    library = models.ForeignKey(Library, null=False, blank=False, default='')
    ...

2
仅为了适应形式而更改模型似乎不太合适。只有在您的模型以这种方式运作时才应该这样做。 - gdvalderrama

0

已接受的解决方案适用于处理关系的字段, 但对于设置了选项字段的模型字段则不起作用。

对于任何在尝试隐藏选项设置时遇到空选择字段的人,我通过为我的模型表单提供自定义CSS使其正常工作。

我不知道在使用默认选择小部件时隐藏空选择字段是否有意义,但在使用RadioSelect小部件时是有意义的。

请确保配置好您的静态文件设置,然后运行python manage.py collectstatic

/* STATICFILES_DIRS/css/my_customizations.css */
#id_field_name :has(input[value='']) {
  visibility: hidden;
  padding: 0;
  margin: 0;
  height: 0;
}

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = "__all__"
        widgets = {"field_name": forms.RadioSelect()}
        # if you're using Django 3.x, you need set the class for inline
        # widgets = {"field_name": forms.RadioSelect(attrs={"class": "inline li"})}

    class Media:
        css = {"all": ("css/my_customizations.css",)}

这让我可以在数据库中最初将选项设置为 null,但确保编写者选择其中两个字段之一,并且不能将其从有效值更改为未设置的值。

然而,截至 2023 年 1 月,:has 尚未被 Firefox 支持,但希望今年某个时候能够支持。


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

0

如果您已将此设置为CharField,请直接转到选项列表并提供以下代码以代替None

另外,请记住,这只是一个示例,与实际代码无关。它只是旨在帮助那些遇到默认选项问题的人。

GENDER_CHOICES = (
    (None, 'Sex:'),
    ('M', 'Male'),
    ('F', 'Female'),
    ('G', 'Gay'),
    ('L', 'Lesbian'),
    ('B', 'Bi'),
    ('O', 'Other')
)
Choose_gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)

通过指定None,您告诉选择字段默认为某个字符串。如果您想要默认为空,请将''空括号放入其中。

使用 (None, ''),仍然会显示一个可选择的框(尽管没有 ---------)。 - SaeX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接