Форматы Django: как динамически создавать метки ModelChoiceField

Я хотел бы создать динамические метки для 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)

Метки по умолчанию определяются функцией unicode, указанной в определении профиля. Однако метки для переключателей, созданных ModelChoiceField, должны создаваться динамически.

Сначала я подумал, что могу просто переопределить ModelChoiceField, как описано в документации Django. Но это создает статические метки. Он позволяет вам определять любую метку, но после выбора этот выбор фиксирован.

Поэтому я думаю, что мне нужно адаптировать что-то добавить к 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>??? = ???

Кто-нибудь знает, как с этим справиться? Любая помощь будет очень признательна.


Я что-то нашел, но не знаю, лучшее ли это решение. Я добавляю что-то в init часть класса ProfileForm следующим образом:

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)

Ответы

Ответ 1

Вы можете использовать ModelChoiceField, а затем динамически изменить выбор в ProfileForm.__init__, например (если предположить, что он уже является ModelChoiceField):

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

h.name в этом примере будет использоваться как метка выбора!

Ответ 2

Вы можете создать свой собственный класс полей формы и перезаписать метод, который генерирует метку:

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

используйте его в своей форме так же, как и с ModelChoiceField:

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

Ответ 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):...'