Django保存Command_Form时创建关联EC_Node实例报错排查
错误根源
报错'BoundField' object has no attribute 'EC_Node_set'来自视图里的两行冗余错误代码:
command_form = form['host_id'] command_form.EC_Node_set.all()
form['host_id']返回的是表单绑定字段对象(BoundField),不是Command_Node模型实例,自然不存在反向关联属性。你已经在表单save()方法中写了创建EC_Node的逻辑,这两行直接删除即可。
现存其他问题
- 表单字段定义位置错误:
host_id、拼写错误的current_comamnds(正确应为current_commands,a和m顺序写反)写在了class Meta内部,Django不会识别Meta嵌套范围内的表单字段,需要直接定义在Form类下。 - 关联记录创建时机错误:当前代码先创建
EC_Node再保存Command_Node实例,此时self.instance还未写入数据库、无主键ID,作为外键关联会触发数据一致性错误。 - 字段类型和控件不匹配:
host_id使用了SelectMultiple多选控件,但字段定义为单选的ModelChoiceField,提交多值时会直接验证失败。 - 反向关联名大小写错误:Django默认反向关联名是全小写的
类名小写_set格式,你写的大驼峰开头EC_Node_set不符合规则,即使拿到正确的模型实例也会报错。
修正后代码
models.py(建议规范命名,减少拼写错误)
如果不想修改原有命名,保持Command_Node/EC_Node/Command_node原名也可,后续代码对应匹配即可:
class Command_Node(models.Model): host_id = models.ForeignKey(Beacon, on_delete=models.CASCADE) current_commands = models.CharField(choices=CHOICES, max_length=50, null=True) def __str__(self): return str(self.host_id) class EC_Node(models.Model): # 加related_name方便后续反向查询,不加的话默认反向名为ec_node_set Command_node = models.ForeignKey(Command_Node, on_delete=models.DO_NOTHING, related_name="ec_records") command = models.CharField(choices=CHOICES, max_length=50, null=True) def __str__(self): return str(self.Command_node)
forms.py
class Command_Form(ModelForm): # 字段直接定义在Form类下,修正拼写错误,多选字段匹配对应类型 host_id = forms.ModelMultipleChoiceField( required=True, queryset=Beacon.objects.all(), widget=forms.SelectMultiple( attrs={ 'class': 'form-control' }, ) ) current_commands = forms.ChoiceField( required=True, choices=CHOICES ) class Meta: model = Command_Node fields = ('host_id','current_commands') def save(self, commit=True): # 先保存主表实例,拿到数据库生成的主键 instance = super().save(commit=commit) # 主表保存成功后再创建关联记录,避免外键关联不存在的ID if commit: EC_Node.objects.create( command=self.cleaned_data["current_commands"], Command_node=instance ) return instance
views.py
def update(request, host_id): host_obj = Command_Node.objects.get(pk=host_id) form = Command_Form(request.POST or None, instance=host_obj) if form.is_valid(): # 直接调用save即可,关联EC_Node的创建逻辑已经封装在表单save方法中 form.save() return redirect('home') return render(request, 'update.html', {'host_id':host_obj,'form':form})
查询方式说明
后续需要获取某个Command_Node下所有关联EC_Node记录时,如果配置了related_name="ec_records",直接调用:
target_host = Command_Node.objects.get(pk=1) all_ec_logs = target_host.ec_records.all()
如果没有配置related_name,使用默认全小写的反向关联名即可:
all_ec_logs = target_host.ec_node_set.all()
内容的提问来源于stack exchange,提问作者Steven Pinkerton
相关产品推荐
相关产品推荐

