Django SelectMultiple 小部件的动态选择

Posted

技术标签:

【中文标题】Django SelectMultiple 小部件的动态选择【英文标题】:Dynamic choices for Django SelectMultiple Widget 【发布时间】:2011-02-07 02:02:51 【问题描述】:

我正在构建一个表单(不是 modelForm),我想使用 SelectMultiple 小部件根据表单初始化期间完成的查询来显示选择。

我可以想到几种方法来做到这一点,但我并不完全清楚正确的方法。我看到了不同的选择。

我得到了我应该以 init 形式传递给小部件的“选择”,但我不确定应该如何传递它们。

class NavigatorExportForm(forms.Form):

def __init__(self,user, app_id, *args,**kwargs):
    super (NavigatorExportForm,self ).__init__(*args,**kwargs) # populates the form
    language_choices = Navigator.admin_objects.get(id=app_id).languages.all().values_list('language', flat=True)

languages = forms.CharField(max_length=2, widget=forms.SelectMultiple(choices=???language_choices))

【问题讨论】:

【参考方案1】:

为什么不改用ModelMultipleChoiceField

你可以这样做:

class NavigatorExportForm(forms.Form):
    languages = forms.ModelMultipleChoiceField(queryset=Language.objects.all())

    def __init__(self, app_id, *args, **kwargs):
        super(NavigatorExportForm, self).__init__(*args, **kwargs)
        # Dynamically refine the queryset for the field
        self.fields['languages'].queryset = Navigator.admin_objects.get(id=app_id).languages.all()

这样,您不仅可以限制小部件上的可用选项,还可以限制字段上的可用选项(这为您提供数据验证)。

使用此方法,小部件中显示的字符串将是Language 对象上的__unicode__ 方法的结果。如果这不是您想要的,您可以编写以下自定义字段,如 ModelChoiceField reference 中所述:

class LanguageMultipleChoiceField(forms.ModelMultipleChoiceField):
    def label_from_instance(self, obj):
        return obj.language_code # for example, depending on your model

并在您的表单中使用此类而不是 ModelMultipleChoiceField

【讨论】:

我见过提到 ModelMultipleChoiceField,但不确定它的用途。现在正在尝试。谢谢。 完美运行,看起来比我的干净一点。再次感谢 mmm 实际上,我在验证表单时收到“AttributeError: 'unicode' object has no attribute 'get'”。我的语言模型确实是一个 char 字段... 您必须提供有关此错误的更多详细信息,它发生在哪个文件中?上下文是什么?它可能来自您清理或操作表单中已清理数据的方式吗?另外,您的意思是:我的语言模型确实是一个字符字段...【参考方案2】:
def __init__(self,user, app_id, *args,**kwargs):
super (NavigatorExportForm,self ).__init__(*args,**kwargs)
self.fields['languages'].widget.choices = Navigator.admin_objects.get(id=app_id).languages.all().values_list('language', flat=True)

这似乎可以解决问题,但即使不指定 max_length,小部件也只会显示选项的第一个字母...

【讨论】:

choices 必须是以下元组的列表/元组 (int_or_str_key, 'name')

以上是关于Django SelectMultiple 小部件的动态选择的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 表单中添加新的相关对象

是否有与 HTML 中的“选择多个”元素等效的小部件

如何在我的自定义小部件模板中包含内置的 django 小部件模板?

Django - DateTime 小部件格式

Django 本地化内置小部件

Django_filters 小部件自定义