Django自定义表单中外键显示pk而非name字段的问题求助
问题:Django表单外键字段显示PK而非Name字段
在编辑Django模型时,表单的外键字段(service和device)在ChoiceTxtField输入框中显示的是模型的PK编号,而非对应的name字段值,需要调整让其显示name字段。
现有代码
forms.py
class ListTextWidget(forms.Select): template_name = 'include/_forms_orders_datalist.html' def format_value(self, value): if value == '' or value is None: return '' if self.is_localized: return formats.localize_input(value) return str(value) class ChoiceTxtField(forms.ModelChoiceField): widget=ListTextWidget() class SimpleOrderEditForm(forms.ModelForm): service = ChoiceTxtField(queryset=Service.objects.order_by('-used')) device = ChoiceTxtField(queryset=Device.objects.order_by('-used')) def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(SimpleOrderEditForm, self).__init__(*args, **kwargs) status_excluded = ['','-'] self.fields['service'].choices = [(k, v) for k, v in self.fields['service'].choices if k not in status_excluded] self.fields['device'].choices = [(k, v) for k, v in self.fields['device'].choices if k not in status_excluded] class Meta: model = Orders fields = ['device','service'] widgets = {}
include/_forms_orders_datalist.html
<input id="ajax_input_{{ widget.name }}" list="{{ widget.name }}" autocomplete="off" {% if widget.value != None %} name="{{ widget.name }}" value="{{ widget.value|stringformat:'s' }}"{% endif %} {% include "django/forms/widgets/attrs.html" %}> {% for group_name, group_choices, group_index in widget.optgroups %} {% for option in group_choices %} <span class="badge rounded-pill bg-warning text-dark" id="list-item-{{ widget.name }}" name="list-item-{{ widget.name }}"> {% include option.template_name with widget=option %}</span> {% endfor %} {% endfor %} <datalist id="{{ widget.name }}"> <optgroup label=""> </optgroup> </datalist>
models.py
class Orders(models.Model): service = models.ForeignKey('Service', default=1, on_delete = models.SET_DEFAULT, null=True, verbose_name='Услуга', related_name='get_service') device = models.ForeignKey('Device', default=1, on_delete = models.SET_DEFAULT, null=True, verbose_name='Устройство', related_name='get_device') class Service(models.Model): name = models.CharField(max_length=150, db_index=True, unique=True, verbose_name='Наименования услуги') def __str__(self): return self.name class Device(models.Model): name = models.CharField(max_length=150, db_index=True, unique=True, verbose_name='Устройство')
解决方案
1. 给Device模型添加__str__方法
Service模型已经定义了__str__返回name,但Device模型缺少该方法,导致choices中的显示值异常。添加后,表单choices的文本会自动使用模型的name字段:
class Device(models.Model): name = models.CharField(max_length=150, db_index=True, unique=True, verbose_name='Устройство') def __str__(self): return self.name
2. 修改ListTextWidget的format_value方法
当前format_value直接返回PK的字符串形式,需要修改为根据PK获取对应模型实例的name值:
from django.core.exceptions import ObjectDoesNotExist class ListTextWidget(forms.Select): template_name = 'include/_forms_orders_datalist.html' def format_value(self, value): if value == '' or value is None: return '' if self.is_localized: return formats.localize_input(value) # 根据PK获取模型实例,返回name字段 try: # 从widget关联的queryset中查询实例 instance = self.choices.queryset.get(pk=value) return instance.name except (ObjectDoesNotExist, AttributeError): # 异常情况下返回原PK值,避免报错 return str(value)
3. (可选)模板层调整显示逻辑
如果不想修改widget,也可以在模板中通过遍历choices找到当前选中项的文本:
{% with selected_text=widget.value|stringformat:'s' %} {% for group_name, group_choices, group_index in widget.optgroups %} {% for option in group_choices %} {% if option.value == widget.value|stringformat:'s' %} {% with selected_text=option.label %} {% endwith %} {% endif %} {% endfor %} {% endfor %} <input id="ajax_input_{{ widget.name }}" list="{{ widget.name }}" autocomplete="off" {% if widget.value != None %} name="{{ widget.name }}" value="{{ selected_text }}"{% endif %} {% include "django/forms/widgets/attrs.html" %}> {% endwith %}
说明
完成上述修改后,表单输入框会显示外键关联模型的name字段值,而非PK编号。其中第一步是基础(保证choices的文本正确),第二步是核心(让input的value显示name),按需选择修改方式即可。
内容的提问来源于stack exchange,提问作者JopaBoga
相关产品推荐
相关产品推荐

