Django Forms提交时新建记录而非更新已有command_node条目问题
问题原因
无参数调用ModelForm的save()方法时,Django默认执行新建模型实例的逻辑,不会自动关联查询选中主机已存在的command_node记录做更新,因此每次提交都会生成全新的关联记录。
修复步骤
1. 修正models.py的错误导入与字段隐患
当前代码中从tkinter、turtle导入的内容属于无效错误导入,直接删除即可;另外外键字段命名为host_id会和Django外键自动生成的_id后缀属性冲突,建议加db_column参数指定数据库列名,避免字段映射混乱。修正后代码:
from django.db import models class beacon(models.Model): host_id = models.BigAutoField('Id', primary_key=True) hostname = models.CharField('Hostname', max_length=200) internalIp = models.CharField('Internal-IP', max_length=200) externalIp = models.CharField('External-IP', max_length=200) current_user = models.CharField('Current_User', max_length=200) os = models.CharField('OS', max_length=200) admin = models.CharField('Admin', max_length=200) def __str__(self): return self.hostname CHOICES = [ ('Sleep', "Sleep"), ('Open SSH_Tunnel', 'Open SSH_Tunnel'), ('Close SSH_Tunnel', 'Close SSH_Tunnel'), ('Open TCP_Tunnel', 'Open TCP_Tunnel'), ('Close TCP_Tunnel', 'Close TCP_Tunnel'), ('Open Dynamic', 'Open Dynamic'), ('Close Dynamic', 'Close Dynamic'), ('Task', 'Task'), ] class command_node(models.Model): host = models.ForeignKey(beacon, on_delete=models.CASCADE, db_column='host_id') current_commands = models.CharField(choices=CHOICES, max_length=50, null=True) previous_commands = models.CharField('previous_commands', max_length=2000, null=True) def __str__(self): return str(self.host)
如果不想修改原有外键字段名
host_id,可以保留原命名,只需把后续视图代码中查询用到的host=参数替换为host_id=即可。
2. 重写视图提交逻辑
不要直接调用form.save(),表单校验通过后,取出选中的目标主机和命令,用Django ORM的update_or_create方法实现「存在即更新、不存在才新建」的逻辑,修正后代码:
from django.shortcuts import render from .models import beacon, command_node from .forms import Command_Form def home(request): form = Command_Form() if request.method == "POST": form = Command_Form(request.POST) if form.is_valid(): # 从清洗后的表单数据取选中的目标主机、待下发命令 target_host = form.cleaned_data['host'] target_command = form.cleaned_data['current_commands'] # 按主机匹配已有command_node记录,更新current_commands字段 command_node.objects.update_or_create( host=target_host, defaults={'current_commands': target_command} ) # 返回空白表单避免重复提交 return render(request, 'home.html', {"form": Command_Form()}) return render(request, 'home.html', {"form": form})
补充说明
- 如果你的
Command_Form中主机选择字段的命名不是host,将上述代码中对应取值、查询的字段名替换为表单实际字段名即可。 - 后续实现「命令执行完成后迁移到历史记录」逻辑时,只需在客户端回调接口中查询对应主机的
command_node记录,将current_commands的值追加到previous_commands后清空current_commands字段即可。 - 修改模型字段后需要重新执行
python manage.py makemigrations和python manage.py migrate同步数据库结构。
内容的提问来源于stack exchange,提问作者Steven Pinkerton
相关产品推荐
相关产品推荐

