开发者

Django forms: how to dynamically create ModelChoiceField labels

开发者 https://www.devze.com 2023-01-01 18:18 出处:网络
I would like to create dynamic labels for a forms.ModelChoiceField and I\'m wondering how to do that. I have the following form class:

I would like to create dynamic labels for a forms.ModelChoiceField and I'm wondering how to do that. I have the following form class:

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, sel开发者_开发知识库f).__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)

The default labels are defined by the unicode function specified in the Profile definition. However the labels for the radio buttons created by the ModelChoiceField need to be created dynamically.

First I thought I could simply override ModelChoiceField as described in the Django documentation. But that creates static labels. It allows you to define any label but once the choice is made, that choice is fixed.

So I think I need to adapt add something to init like:

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>??? = ???

Anyone having any idea how to handle this? Any help would be appreciated very much.


I found something but I don't know if it's the best solution. I add something to the init part of class ProfileForm as follows:

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)


You could use a ModelChoiceField and then change the choices in you ProfileForm.__init__ dynamically, eg (assuming that it is already a ModelChoiceField):

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

h.name in this example will be used as the label of the choice!


You can make your own form field class and overwrite the method that generates the label:

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

use it in your form same as you did with the ModelChoiceField:

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


Actually the last code example contains errors an should be:

# 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

Then it works. There is no difference in using 'lambda obj:...' or 'def get_label(obj): ...'

0

精彩评论

暂无评论...
验证码 换一张
取 消