Для этого можно, например, установить патч prepare_value
[GitHub] и 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="...">
s. С другой стороны, функция to_python
выполняет преобразование обратно в объект firearm
(или None
, если выбор пуст).
Вы должны будете убедиться, что две функции являются друг другу обратными : каждое сопоставление с prepare_value
должно приводить к одному и тому же объекту, когда мы выполняем to_python
над ним. Если, например, здесь make
содержит двоеточие (:
), то произойдет сбой, поэтому может потребоваться дополнительная настройка.
При этом я не уверен, почему вы хотите использовать более сложное значение и не использовать для этого первичный ключ, слаг или какое-то хеш-значение.