You can patch the prepare_value
[GitHub] and to_python
[GitHub] functions for that, for example:
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')
You thus should not specify the field_name
here. In fact if we look at the original implemention, we see how this field_name
is used:
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
In the prepare_value
, we thus convert an object (here a firearm_db
object) into a string that holds the value used in the <option value="...">
s. The to_python
function on the other hand performs the transformation back to a firearm
object (or None
in case the selection is empty).
You will have to ensure that the two functions are each other inverse: each mapping with prepare_value
should result in the same object when we perform a to_python
on it. If for example here the make
contains a colon (:
), then this will fail, so it might require some extra finetuning.
That being said, I am not sure why you want to use a more complicated value, and not use a primary key, a slug, or some hashed value for this.