您可以为此修补prepare_value
[GitHub]和to_python
[GitHub]函数,例如:
from django.core.exceptions import ValidationError
class firearmChoiceField(forms.ModelChoiceField):
def prepare_value(self, value):
if hasattr(value, '_meta'):
return '{}:{}:{}'.format(value.make,value.firearm_model,value.serial_no)
return super().prepare_value(value)
def to_python(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.to_field_name:
return value.serializable_value(self.to_field_name)
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.to_field_name 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="...">
s 中使用的值。to_python
另一方面,该函数执行转换回firearm
对象(或None
在选择为空的情况下)。
您必须确保这两个函数互为逆:当我们对其执行 a 时,每个映射 withprepare_value
都应该产生相同的对象to_python
。例如,如果这里make
包含一个冒号 ( :
),那么这将失败,因此可能需要一些额外的微调。
话虽如此,我不确定您为什么要使用更复杂的值,而不是为此使用主键、slug 或一些散列值。