Форматы 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):...'