Py学习  »  Django

自定义/删除Django选择框空白选项

jlpp • 6 年前 • 1368 次点击  

我用的是django 1.0.2。我写了一个模型表单,由一个模型支持。这个模型有一个foreignkey,其中blank=false。当Django为此表单生成HTML时,它会为ForeignKey引用的表中的每一行创建一个带有一个选项的选择框。它还会在列表顶部创建一个没有值的选项,并显示为一系列短划线:

<option value="">---------</option>

我想知道的是:

  1. 从选择框中删除自动生成的选项最干净的方法是什么?
  2. 最干净的自定义方式是什么,以便显示为:

    <option value="">Select Item</option>
    

在寻找解决方案时,我遇到了 Django ticket 4653 这让我觉得其他人也有同样的问题,Django的默认行为可能已经被修改了。这张票已经一年多了,所以我希望有一个更清洁的方法来完成这些事情。

谢谢你的帮助,

杰夫

编辑:我已经配置了foreignkey字段,如下所示:

verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)

这确实设置了默认值,因此它不再是空/破折号选项,但不幸的是,它似乎无法解决我的任何问题。也就是说,空/短划线选项仍然显示在列表中。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/30690
 
1368 次点击  
文章 [ 15 ]  |  最新文章 6 年前
Ibo
Reply   •   1 楼
Ibo    6 年前

选择是外键 如果你想的话 根据某些条件筛选选项 . 在这种情况下,如果您设置 empty_label 然后重新分配选项(您也可以在此处应用过滤),空标签将为空:

class ThingForm(models.ModelForm):

    class Meta:
    model = Thing

    def __init__(self, *args, **kwargs):
        super(ThingForm, self).__init__(*args, **kwargs)
        self.fields['verb'].empty_label = None
        self.fields['verb'].queryset=Verb.objects.all()

B基本上,下面的第一行 init 可以应用于窗体中具有循环或内联循环的所有字段:

def __init__(self,user, *args, **kwargs):
    super(NewTicket, self).__init__(*args, **kwargs)
    for f in self.fields:
       self.fields[f].empty_label = None # or "Please Select" etc
Rebecca Koeser
Reply   •   2 楼
Rebecca Koeser    7 年前

由于Django 1.7,您可以通过在模型字段定义中向您的选择列表中添加值来自定义空白值的标签。从有关配置的文档 field choices :

除非在字段上设置blank=false和默认值,否则将使用“选择”框呈现包含“-------”的标签。若要重写此行为,请将元组添加到不包含任何值的选项中;例如,(none,“your string for display”)。或者,您可以使用空字符串而不是无字符串,这是有意义的,例如在charfield上。

我检查了不同版本的Django的文档,发现 added in Django 1.7 .

Jamie Counsell
Reply   •   3 楼
Jamie Counsell    7 年前

这里有很多很好的答案,但是我仍然不完全满意这些实现。我也有点沮丧,因为从不同来源(外键、选项)选择小部件会产生不同的行为。

我有一个设计,我正在和where select字段一起工作 总是 有一个空白选项,如果需要,它们旁边会有一个星号,如果它们是空的,表单将不会验证。也就是说,我只能正确地覆盖字段的空标签 TypedChoiceField S.

结果是这样的 应该 看起来像。第一个结果总是字段的名称-在我的例子中, label .

select widget

这就是我最后做的。以下是重写的 __init__ 我的表格方法:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for _, field in self.fields.items():
        if hasattr(field, 'empty_label'):
            field.empty_label = field.label
        if isinstance(field, forms.TypedChoiceField):
            field.choices = [('', field.label)] + [choice for choice in field.choices if choice[0]]
user3002411
Reply   •   4 楼
user3002411    11 年前

我找到了解决办法!!

但不适用于foreignkey:-)

也许我能帮你。 我查看了django源代码,发现在django.forms.extras.widgets.selectedatewidget()中,一个名为none_value的属性等于(0,-----),所以我在代码中这样做了

class StudentForm(ModelForm):
    class Meta:
        this_year = int(datetime.datetime.today().strftime('%Y')) 
        birth_years = []
        years = []

        for year in range(this_year - 2, this_year + 3 ):
            years.append(year)
        for year in range(this_year - 60, this_year+2):
            birth_years.append(year)

        model = Student
        exclude = ['user', 'fullname']
        date_widget = SelectDateWidget(years=years)

        date_widget.__setattr__('none_value', (0, 'THERE WAS THAT "-----" NO THERES THIS:-)'))
        widgets = {
            'beginning': date_widget,
            'birth': SelectDateWidget(years=birth_years),
        }
YPCrumble
Reply   •   5 楼
YPCrumble    7 年前

对于一个 ForeignKey 字段,设置 default 价值到 '' 对模型将去掉空白选项。

verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='')

其他领域如 CharField 你可以设置 违约 None 但这不适用于 外键 Django 1.11中的字段。

lwj0012
Reply   •   6 楼
lwj0012    10 年前

最新版本的Django 第一个答案应该是这样的

class ThingForm(models.ModelForm):
class Meta:
 model = Thing

  def __init__(self, *args, **kwargs):
    self.base_fields['cargo'].empty_label = None
    super(ThingForm, self).__init__(*args, **kwargs)`
emyller
Reply   •   7 楼
emyller    11 年前

我今天把这件事搞得一团糟,就想出了一个 胆小鬼 俏皮的解决方案:

# Cowardly handle ModelChoiceField empty label
# we all hate that '-----' thing
class ModelChoiceField_init_hack(object):
    @property
    def empty_label(self):
        return self._empty_label

    @empty_label.setter
    def empty_label(self, value):
        self._empty_label = value
        if value and value.startswith('-'):
            self._empty_label = 'Select an option'
ModelChoiceField.__bases__ += (ModelChoiceField_init_hack,)

现在您可以调整默认值 ModelChoiceField 任何你想要的东西都要空标签。-)

附言:不需要投反对票,无害的猴子补丁总是很方便的。

Mithril
Reply   •   8 楼
Mithril    9 年前

self.fields['xxx'].empty_value = None 如果字段类型为 TypedChoiceField 哪个没有 empty_label 财产。

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

1。如果你想建立一个 BaseForm 自动检测 类型dchoicefield

class BaseForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(BaseForm, 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:]
            # code to process other Field
            # ....

class AddClientForm(BaseForm):
     pass

2.只有几种形式,您可以使用:

class AddClientForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(AddClientForm, self).__init__(*args, **kwargs)
        self.fields['xxx'].choices = self.fields['xxx'].choices[1:]
holmes86
Reply   •   9 楼
holmes86    12 年前

您可以在“管理”中执行此操作:

formfield_overrides = {
    models.ForeignKey: {'empty_label': None},
}
Thomas B. Higgins
Reply   •   10 楼
Thomas B. Higgins    15 年前

here 关于这个问题的完整辩论和解决方法。

ykhrustalev
Reply   •   11 楼
ykhrustalev    12 年前

对于django 1.4,您只需要在选项字段上设置“默认”值和“blank=false”。

class MyModel(models.Model):
    CHOICES = (
        (0, 'A'), 
        (1, 'B'),
    )
    choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)
Lu.nemec
Reply   •   12 楼
Lu.nemec    11 年前

您可以在您的模型上使用:

class MyModel(models.Model):
    name = CharField('fieldname', max_length=10, default=None)

缺省=无 答案是:d

注:我在Django 1.7上试过这个。

jlpp
Reply   •   13 楼
jlpp    16 年前

以卡尔的回答为指导,在围绕Django源搜索了几个小时后,我认为这是完整的解决方案:

  1. 要删除空选项(扩展Carl的示例):

    class ThingForm(models.ModelForm):
      class Meta:
        model = Thing
    
      def __init__(self, *args, **kwargs):
        super(ThingForm, self).__init__(*args, **kwargs)
        self.fields['verb'].empty_label = None
        # following line needed to refresh widget copy of choice list
        self.fields['verb'].widget.choices =
          self.fields['verb'].choices
    
  2. 要自定义空选项标签,基本上是相同的:

    class ThingForm(models.ModelForm):
      class Meta:
        model = Thing
    
      def __init__(self, *args, **kwargs):
        super(ThingForm, self).__init__(*args, **kwargs)
        self.fields['verb'].empty_label = "Select a Verb"
        # following line needed to refresh widget copy of choice list
        self.fields['verb'].widget.choices =
          self.fields['verb'].choices
    

我认为这种方法适用于所有将modelchoiceFields呈现为HTML的场景,但我并不乐观。我发现当初始化这些字段时,它们的选择会传递到select小部件(请参见django.forms.fields.choiceField.\u set_choices)。初始化后设置空的_标签不会刷新选择小部件的选择列表。我对Django不够熟悉,不知道这是否应该被视为bug。

zalew
Reply   •   14 楼
zalew    16 年前

从文档

空白选项将不包括在内。 如果模型字段为空=假,并且 显式默认值(默认值 最初将选择值 取而代之的是)

所以设置默认值就可以了

Carl Meyer
Reply   •   15 楼
Carl Meyer    16 年前

还没有测试过这个,但是基于读取Django的代码 here here 我认为它应该起作用:

class ThingForm(models.ModelForm):
  class Meta:
    model = Thing

  def __init__(self, *args, **kwargs):
    super(ThingForm, self).__init__(*args, **kwargs)
    self.fields['verb'].empty_label = None

编辑 这是 documented 但是,如果使用自动生成的模型窗体,则不一定知道要查找ModelChoiceField。

编辑 :正如jlpp在他的回答中指出的,这并不完整-您必须在更改空的_label属性后将选项重新分配给小部件。由于这有点老土,另一个可能更容易理解的选项就是覆盖整个ModelChoiceField:

class ThingForm(models.ModelForm):
  verb = ModelChoiceField(Verb.objects.all(), empty_label=None)

  class Meta:
    model = Thing