在 forms.py 中,当我将 "to_field_name" 设置为多个列名称时,出现错误
in forms.py when i set "to_field_name" to more than one column name, it's giving me error
我为 modelchoicefield 创建了一个 label_form_instance,但 html 中的值显示的是主键值。为了摆脱这一点,我使用 to_field_names 但我不能在其中提供多个列名称。
class firearmChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return '%s%s, %s'%(obj.make,obj.firearm_model,obj.serial_no)
self.fields['firearm'] = firearmChoiceField(queryset = firearm_db.objects.all(),to_field_name="make,firearm_model,serial_no",required=False,empty_label='Select Firearm', widget = forms.Select(attrs={'label': ' ','class': 'form-control',}))
您可以为此修补 prepare_value
[GitHub] and to_python
[GitHub] 函数,例如:
from django.core.exceptions import ValidationError
class firearmChoiceField(forms.ModelChoiceField):
def <b>prepare_value</b>(self, value):
if hasattr(value, '_meta'):
return '{}:{}:{}'.format(value.make,value.firearm_model,value.serial_no)
return super().prepare_value(value)
def <b>to_python</b>(self, value):
if value in self.empty_values:
return None
try:
make, firmod, serial = value.split(':')
return firearm_db.objects.get(
make=make,
firearm_model=firmod,
serial_no=serial
)
except (ValueError, TypeError, firearm_db.DoesNotExist):
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
因此您应该不在此处指定field_name
。事实上,如果我们查看原始实现,我们会看到这个 field_name
是如何使用的:
class ModelChoiceField(ChoiceField):
# ...
def prepare_value(self, value):
if hasattr(value, '_meta'):
if self.<b>to_field_name</b>:
return value.serializable_value(self.<b>to_field_name</b>)
else:
return value.pk
return super().prepare_value(value)
def to_python(self, value):
if value in self.empty_values:
return None
try:
key = self.<b>to_field_name</b> or 'pk'
value = self.queryset.get(**{key: value})
except (ValueError, TypeError, self.queryset.model.DoesNotExist):
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
return value
在prepare_value
中,我们因此将一个对象(这里是一个firearm_db
对象)转换成一个字符串,其中包含在<option value="...">
中使用的值。另一方面,to_python
函数执行转换回 firearm
对象(或 None
,以防选择为空)。
你必须确保这两个函数是彼此 inverse:当我们执行 [=11] 时,每个 prepare_value
的映射应该产生相同的对象=] 就可以了。例如,如果 make
包含一个冒号 (:
),那么这将失败,因此可能需要一些额外的微调。
话虽这么说,但我不确定您为什么要使用更复杂的值,而不是为此使用主键、slug 或某些散列值。
我为 modelchoicefield 创建了一个 label_form_instance,但 html 中的值显示的是主键值。为了摆脱这一点,我使用 to_field_names 但我不能在其中提供多个列名称。
class firearmChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return '%s%s, %s'%(obj.make,obj.firearm_model,obj.serial_no)
self.fields['firearm'] = firearmChoiceField(queryset = firearm_db.objects.all(),to_field_name="make,firearm_model,serial_no",required=False,empty_label='Select Firearm', widget = forms.Select(attrs={'label': ' ','class': 'form-control',}))
您可以为此修补 prepare_value
[GitHub] and to_python
[GitHub] 函数,例如:
from django.core.exceptions import ValidationError
class firearmChoiceField(forms.ModelChoiceField):
def <b>prepare_value</b>(self, value):
if hasattr(value, '_meta'):
return '{}:{}:{}'.format(value.make,value.firearm_model,value.serial_no)
return super().prepare_value(value)
def <b>to_python</b>(self, value):
if value in self.empty_values:
return None
try:
make, firmod, serial = value.split(':')
return firearm_db.objects.get(
make=make,
firearm_model=firmod,
serial_no=serial
)
except (ValueError, TypeError, firearm_db.DoesNotExist):
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
因此您应该不在此处指定field_name
。事实上,如果我们查看原始实现,我们会看到这个 field_name
是如何使用的:
class ModelChoiceField(ChoiceField): # ... def prepare_value(self, value): if hasattr(value, '_meta'): if self.<b>to_field_name</b>: return value.serializable_value(self.<b>to_field_name</b>) else: return value.pk return super().prepare_value(value) def to_python(self, value): if value in self.empty_values: return None try: key = self.<b>to_field_name</b> or 'pk' value = self.queryset.get(**{key: value}) except (ValueError, TypeError, self.queryset.model.DoesNotExist): raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice') return value
在prepare_value
中,我们因此将一个对象(这里是一个firearm_db
对象)转换成一个字符串,其中包含在<option value="...">
中使用的值。另一方面,to_python
函数执行转换回 firearm
对象(或 None
,以防选择为空)。
你必须确保这两个函数是彼此 inverse:当我们执行 [=11] 时,每个 prepare_value
的映射应该产生相同的对象=] 就可以了。例如,如果 make
包含一个冒号 (:
),那么这将失败,因此可能需要一些额外的微调。
话虽这么说,但我不确定您为什么要使用更复杂的值,而不是为此使用主键、slug 或某些散列值。