1

我为 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',}))
4

1 回答 1

0

您可以为此修补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 或一些散列值。

于 2019-05-11T21:08:38.800 回答