在 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 或某些散列值。