【问题标题】:Populate a Django form field with choices from database (but not from a model)使用来自数据库(但不是来自模型)的选择填充 Django 表单字段
【发布时间】:2019-10-22 04:12:24
【问题描述】:

我想用数据库中的数据填充表单下拉列表。 这些数据并非直接来自模型,而是来自原始查询。

当数据库可用且已生成迁移时,此功能有效。否则,生成迁移 (python manage.py makemigrations myapp) 将失败,因为 Django 评估 _all_departments() 无法找到合适的表。

def _all_departments() -> List[Tuple[str, str]]:
    from django.db import connection
    with connection.cursor() as cursor:
        cursor.execute("select distinct department from crm_mytable order by department")
        return [(row[0], row[0]) for row in cursor.fetchall()]


class MyForm(forms.Form):
    department = forms.CharField(
        widget=forms.SelectMultiple(choices=_all_departments()))

我天真地尝试手动更新__init__ 上的选择但没有成功(选择始终为空):

class MyForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['department'].widget.choices = _all_departments()

    department = forms.CharField(
        widget=forms.SelectMultiple(choices=[]))

如何正确填写按需选择?

【问题讨论】:

  • 您的第一个解决方案不起作用,因为您可能正在视图中的某处导入 MyForm(在任何 manage.py 操作期间启动 django 时导入),因此函数 @987654327 @ 被评估。您的第二个解决方案应该可以工作。
  • 作为一个兴趣点,你为什么不定义一个模型来表示你的部门表?
  • 我没有充分的理由不这样做。顺便说一句,在实际应用程序中,我可能会这样做。我正在开发的应用程序更像是一个发现和评估 Django 功能的玩具。

标签: django django-forms


【解决方案1】:

您不应该choices 传递给小部件,而是传递给字段。您还可能想使用MultipleChoiceField [Django-doc],这使用SelectMultiple [Django-doc] 作为默认小部件:

class MyForm(forms.Form):

    department = forms.MultipleChoiceField(choices=[])

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['department'].choices = _all_departments()

【讨论】:

  • 同意 MultipleChoiceField 是更好的路径,但为什么在小部件上设置选项不起作用?一个ChoiceWidget(它是SelectMultiple 的父级)在其初始化程序中有choices,它设置了它的属性choices,那为什么不起作用呢?
  • @dirkgroten: 因为 field 验证选项是否为 valid,实际上小部件只与该字段“对话”并指定如何呈现选择。 Widget 仅指定如何渲染 某物,而不是如何检索 某物、验证某物等。
  • 但他使用的是 CharField,它不会验证选择并强制将小部件接收到的列表强制转换为文本。我至少希望小部件使用选项呈现,并且 Charfield 将列表作为字符串返回。
  • @dirkgoten:当您构造 Field 时(请注意,这发生在 您构造了小部件之后),它将其选择设置为小部件的选择:@987654323 @
  • 字段是在 super().__init__() 中构造的不是吗?因此,在构造字段后会覆盖小部件选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 2014-03-20
  • 2020-05-08
  • 2021-11-19
  • 2020-03-18
  • 2012-09-14
  • 1970-01-01
相关资源
最近更新 更多