【问题标题】:Django forms: how to dynamically create ModelChoiceField labelsDjango 表单:如何动态创建 ModelChoiceField 标签
【发布时间】:2010-06-02 14:46:33
【问题描述】:

我想为 forms.ModelChoiceField 创建动态标签,我想知道该怎么做。我有以下表单类:

class ProfileForm(forms.ModelForm):

    def __init__(self, data=None, ..., language_code='en', family_name_label='Family name', horoscope_label='Horoscope type', *args, **kwargs):
        super(ProfileForm, self).__init__(data, *args, **kwargs)

        self.fields['family_name'].label = family_name_label
        .
        .
        self.fields['horoscope'].label = horoscope_label
        self.fields['horoscope'].queryset = Horoscope.objects.all()

    class Meta:
        model = Profile

    family_name = forms.CharField(widget=forms.TextInput(attrs={'size':'80', 'class': 'contact_form'}))
    .
    .
    horoscope = forms.ModelChoiceField(queryset = Horoscope.objects.none(), widget=forms.RadioSelect(), empty_label=None)

默认标签由 Profile 定义中指定的 unicode 函数定义。但是,ModelChoiceField 创建的单选按钮的标签需要动态创建。

首先,我认为我可以按照 Django 文档中的描述简单地覆盖 ModelChoiceField。但这会创建静态标签。它允许您定义任何标签,但一旦做出选择,该选择就固定了。

所以我认为我需要适应向 init 添加一些内容,例如:

class ProfileForm(forms.ModelForm):

    def __init__(self, data=None, ..., language_code='en', family_name_label='Family name', horoscope_label='Horoscope type', *args, **kwargs):
        super(ProfileForm, self).__init__(data, *args, **kwargs)

        self.fields['family_name'].label = family_name_label
        .
        .
        self.fields['horoscope'].label = horoscope_label
        self.fields['horoscope'].queryset = Horoscope.objects.all()
        self.fields['horoscope'].<WHAT>??? = ???

有人知道如何处理这个问题吗?任何帮助将不胜感激。


我找到了一些东西,但我不知道这是否是最佳解决方案。我向 ProfileForm 类的 init 部分添加如下内容:

class ProfileForm((forms.ModelForm):

    def __init__(self, data=None, ..., language_code='en', family_name_label='Family name', horoscope_label='Horoscope type', *args, **kwargs):
    super(ProfileForm, self).__init__(data, *args, **kwargs)

        # this function is added
        def get_label(self, language_code):
            """
            returns the label in the designated language, from a related object (table)
            """
            return HoroscopeLanguage.objects.get(horoscope=obj, language__language_code=language_code).horoscope_type_language

        self.fields['family_name'].label = family_name_label
        .
        .
        self.fields['horoscope'].queryset = Horoscope.objects.all()
        self.fields['horoscope'].label_from_instance = lambda obj: "%s: Euro %.2f" % (HoroscopeLanguage.objects.get(horoscope=obj, language__language_code=language_code).horoscope_type_language, obj.price)
        .
        .
        """
        The next code also works, the lambda function without the get_label function
        """
        self.fields['horoscope'].label_from_instance = lambda obj: "%s: Euro %.2f" % (obj.horoscope_type, obj.price)
        .
        .
        """
        But this code doesn't work. Anyone?
        """
        self.fields['horoscope'].label_from_instance = get_label(obj, language_code)

【问题讨论】:

  • 您的意思是“默认标签是在 Horoscope 定义中指定的unicode 函数中定义的”?

标签: django django-forms


【解决方案1】:

您可以使用ModelChoiceField,然后动态更改ProfileForm.__init__ 中的选项,例如(假设它已经是一个ModelChoiceField):

horoscopes = Horoscope.objects.all()
self.fields['horoscope'].choices = [(h.pk, h.name) for h in horoscopes]

h.name 在此示例中将用作选择的标签!

【讨论】:

  • 当我尝试您的解决方案时出现错误:“选择一个有效的选项。该选项不是可用选项之一。”恐怕你的解决方案不起作用。基本上,模型 Profile 已经定义了一个外键星座,而 Profile 实例需要一个模型星座的实例,而不仅仅是一个整数 h.pk。
  • 是的,我的意思是“默认标签是在星座定义中指定的 unicode 函数中定义的”
  • 抱歉,我在这里搞错了,它可能适用于普通的 ChoiceField,但请参阅我的其他解决方案,将 ModelChoiceField 子类化!
【解决方案2】:

您可以制作自己的表单字段类并覆盖生成标签的方法:

class MyChoiceField(ModelChoiceField):
   def label_from_instance(self, obj):
        # return your own label here...
        return smart_unicode(obj)

在您的表单中使用它,就像使用 ModelChoiceField 一样:

horoscope = MyChoiceField(queryset = .....)

【讨论】:

  • 是的,这也是我在原始问题中所写的。这将创建替代标签,但 STATIC 标签。请参阅我的评论,上面写着“首先我认为我可以按照 Django 文档中的描述简单地覆盖 ModelChoiceField...”
【解决方案3】:

实际上最后一个代码示例包含错误应该是:

# this function is added
def get_label(obj):
    return '%s: Euro %.2f' % (HoroscopeLanguage.objects.get(horoscope=obj, language__language_code=language_code).horoscope_type_language, obj.price)
.
.
.

self.fields['horoscope'].label_from_instance = get_labels

然后就可以了。使用 'lambda obj:...' 或 'def get_label(obj): ...' 没有区别

【讨论】:

    猜你喜欢
    • 2013-02-19
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2016-11-11
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多