【问题标题】:How to create dropdown box with forms.ModelForm in Django?如何在 Django 中使用 forms.ModelForm 创建下拉框?
【发布时间】:2021-05-23 21:44:46
【问题描述】:

我正在尝试在我的表单中添加一个选项下拉框。我尝试了什么:

from django import forms
from .models import Car

class CarForm(forms.ModelForm):
    owner_name = forms.CharField(max_length=100, label='Owner Name', required=True)
    car_type = forms.ChoiceField(choices=Car.CarTypes.choices, label='Car Type', required=True)

    class Meta:
        model = Car
        fields = ('owner_name', 'car_type')

它将car_type 字段添加到表单中,但由于某种原因它不是下拉列表(它是一个您可以填写的常规空框)。 CarTypes 看起来像:

    class CarTypes(models.TextChoices):
        X = 'some_x'
        Y = 'somy_y'
        # ...

可能是什么原因?

在我的Car 课程中,我有:car_type = models.CharField(max_length=24, choices=CarTypes.choices, default=CarTypes.X)。可以吗?我认为CharField 使它成为空盒子。但将其更改为ChoiceField 以:module 'django.db.models' has no attribute 'ChoiceField' 结尾。如何解决?

我试过这个approach,但它使用元组而不是类。从那里的示例中,我看到他们使用像(('a','A'),('b','B')) 这样的二值元组的元组,而我正在使用类。会不会是这个原因?

在我的 html 中,我有:

    <form method="post" class="form-group">
      {% csrf_token %}
      {% for field in form %}
        <div class="form-group col-md-12 mb-3">
          <label for="{{ field.label }}">{{ field.label }}</label>
          <input type="text" class="form-control" id="{{ field.label }}" name="{{ field.name }}">
        </div>
      {% endfor %}
      <hr class="mb-4">
      <button type="submit" class="btn btn-secondary btn-lg btn-block">Submit New Car</button>
    </form>

汽车看起来像:


class Car(models.Model):

    class CarTypes(models.TextChoices):
        X = 'some_x'
        Y = 'somy_y'
        # ...

    owner_name = models.CharField(max_length=100,unique=True)
    car_type = models.CharField(max_length=24, choices=CarTypes.choices, default=CarTypes.X)

    def __str__(self):
        return self.owner_name

【问题讨论】:

  • 分享您的模型Car。 Django 版本?

标签: python django forms


【解决方案1】:

您不需要覆盖模型字段。见Field types - Django Docs

如果模型字段设置了选项,那么表单字段的小部件将 设置为 Select,选择来自模型字段的选择。

下面的代码应该做你想做的事:

forms.py

from django import forms
from .models import Car

class CarForm(forms.ModelForm):
    class Meta: 
        model = Car 
        fields = ['owner_name', 'car_type']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['owner_name'].widget.attrs.update({"class": "form-control"})
        # or iterate over field to add class for each field
        for field in self.fields:
            self.fields[field].widget.attrs.update({'class':"form-control"})

您可以在__init__ 方法中添加任何html 属性。

html:

<form method="post" class="form-group">
  {% csrf_token %}
    <div class="form-group col-md-12 mb-3">
      <label for="{{ form.owner_name.label }}">{{ form.owner_name.label }}</label>
      {{ form.owner_name }}
    </div>

    <div class="form-group col-md-12 mb-3">
        <label for="{{ form.car_type.label }}">{{ form.car_type.label }}</label>
        {{ form.car_type }}
    </div>
  <hr class="mb-4">
  <button type="submit" class="btn btn-secondary btn-lg btn-block">Submit New Car</button>
</form>

或者您可以使用 {{ form.as_p }} - Django Docs 将它们呈现在 &lt;p&gt; 标签中

更新


手动渲染表单:

<form method="post" class="form-group">
    {% csrf_token %}
    <div class="form-group col-md-12 mb-3">
        <label for="{{ form.owner_name.label }}">{{ form.owner_name.label }}</label>
        <input type="text" class="form-control" id="{{ form.owner_name.auto_id }}" name="{{ form.owner_name.name }}">
    </div>

    <div class="form-group col-md-12 mb-3">
        <label for="{{ form.car_type.label }}">{{ form.car_type.label }}</label>
        <select id="{{ form.car_type.auto_id }}" name="{{ form.car_type.name }}">
        {% for value, label in form.fields.car_type.choices %}
            <option value="{{ value }}"{% if form.car_type.value == value %} selected{% endif %}>{{ label }}</option>
        {% endfor %}
        </select>
    </div>
  <hr class="mb-4">
  <button type="submit" class="btn btn-secondary btn-lg btn-block">Submit New Car</button>
</form>

【讨论】:

  • 我使用了{{ field }} 而不是我的input 部分。但是如何使用class="form-control" id="{{ field.label }}" name="{{ field.name }}" 自定义它?
  • @vesii,您可以在 init 方法中添加任何 html 属性。
  • 可以在 HTML 本身中做吗?
  • 您必须手动渲染输入。
  • 另外,你知道为什么__init__ 没有被执行吗?在Meta__init__ 中都添加了打印,但__init__ 不打印任何内容(并且不添加表单控件)。
【解决方案2】:

对于 Django 3.1,您可以使用 widgets 实现此目的。以下是如何完成它:

from django.forms import ModelForm, Select, TextInput
from .models import Car

class CarForm(ModelForm):
    class Meta:
        model = Car
        fields = ('owner_name', 'car_type')
        widgets = {
            'owner_name': TextInput(),
            'car_type': Select(),
        }

模型应该是这样的:

    class Car(models.Model):
        choices = [('X':'some_x'), ('Y': 'some_y']
        owner_name = models.CharField(max_length=100,unique=True)
        car_type = models.CharField(max_length=24, choices=choices, default='some_y')

        def __str__(self):
            return self.owner_name```

【讨论】:

  • forms.ChoiceField ModelFormchoices 吗?从第二个答案我得到TypeError: __init__() got an unexpected keyword argument 'choices' 因为 forms.ModelForm 在 CharField 中没有选择
【解决方案3】:

尝试使用Choices这个方法:-

models.py

choices = [
    ('choice1', 'choice1'),
    ('choice2',"choice2"),
    ('choice3',"choice3")
]

class Car(models.Model):

    owner_name = models.CharField(max_length=100,unique=True)
    car_type = models.CharField(max_length=24, choices=choices, default='choice1')

    def __str__(self):
        return self.owner_name

然后别忘了migrations

参考这个--->https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.Field.choices

【讨论】:

  • 我得到TypeError: __init__() got an unexpected keyword argument 'choices' 因为forms.ModelFormCharField 中没有选择。
  • 你如何保持它的等级?
  • 只需删除现有模型中的choice Class CarTypes
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 1970-01-01
  • 2012-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多