底部的解决方案
问题: Django 表单填充了对象列表,而不是值
摘要:我有 2 个模型实体和中断。 Breaks 与 Entities 模型上的 entity_id(不是 PK)具有 FK 关系。
我想为Breaks的所有字段生成一个空表单。生成基本表单会填充所有空字段,但对于 FK,它会生成 Entities 表的所有 objects 的下拉列表。这没有帮助,所以我在下面的 ModelForm 中排除了它,并尝试用 Entities 表的所有 entity_ids 列表替换。此表单按预期呈现。
class BreakForm(ModelForm):
class Meta:
model = Breaks
#fields = '__all__'
exclude = ('entity',)
def __init__(self, *args, **kwargs):
super(BreakForm, self).__init__(*args, **kwargs)
self.fields['entity_id'] = ModelChoiceField(queryset=Entities.objects.all().values_list('entity_id', flat=True))
下面的FormView就是URL调用的cbv。如下所示,如果我填充表单,并且对于 FK 列 entity_id 选择其中一个值,则表单将不会提交。表单模板上的该字段将显示以下消息 选择有效选项。该选择不是可用的选择之一。
class ContactFormView(FormView):
template_name = "breaks/test/breaks_form.html"
form_class = BreakForm
我最初的想法是该字段的数据类型(字符串/整数)错误,或者 Django 需要 Entities 表中的行的 PK(无论出于何种原因)。
因此,我向 FormView 添加了一个 post 函数,并且可以看到 request.body 已正确填充。但是我不知道如何将其填充到 ModelForm 中并保存到数据库,或克服上述问题。
附录:
添加的型号如下:
class Entity(models.Model):
pk_securities = models.AutoField(primary_key=True)
entity_id = models.CharField(unique=True)
entity_description = models.CharField(blank=True, null=True)
class Meta:
managed = False
db_table = 'entities'
class Breaks(models.Model):
pk_break = models.AutoField(primary_key=True)
date = models.DateField(blank=True, null=True)
entity = models.ForeignKey(Entity, on_delete= models.CASCADE, to_field='entity_id')
commentary = models.CharField(blank=True, null=True)
active = models.BooleanField()
def get_absolute_url(self):
return reverse(
"item-update", args=[str(self.pk_break)]
)
def __str__(self):
return f"{self.pk_break}"
class Meta:
managed = False
db_table = 'breaks'
解决方案
首先,我通过将以下内容添加到实体模型类来实现此功能。然而我不喜欢这个,因为它会在其他地方产生后果。
def __str__(self):
return f"{self.entity_id}"
我在主题上找到了这个SO线程。接受的答案非常棒,对其的评论也很有帮助。 解决方案是子类化
ModelChoiceField
并覆盖 label_from_instance
class EntityChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return obj.entity_id
我认为你的问题有两个,首先是没有正确渲染下拉列表,第二是表单没有保存。对于第一个问题,您不需要在
ModelChoiceField
查询集中进行任何更改,而是添加 to_field_name
:
class BreakForm(ModelForm):
class Meta:
model = Breaks
#fields = '__all__'
def __init__(self, *args, **kwargs):
super(BreakForm, self).__init__(*args, **kwargs)
self.fields['entity_id'] = ModelChoiceField(queryset=Entities.objects.all(), to_field_name='entity_id')
CreateView
:
class ContactFormView(CreateView):
template_name = "breaks/test/breaks_form.html"
form_class = BreakForm
model = Breaks
解决方案
首先,我通过将以下内容添加到实体模型类来实现此功能。然而我不喜欢这个,因为它会在其他地方产生后果。
def __str__(self):
return f"{self.entity_id}"
我发现了这个主题的主题。接受的答案非常棒,对其的评论也很有帮助。解决方案是子类化 ModelChoiceField 并覆盖 label_from_instance
class EntityChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return obj.entity_id