Django同一模型下两个User外键更新时被同时修改问题排查
Django两个外键字段同时更新问题排查与修复
问题原因
- 视图层ModelForm构造逻辑严重错误
instance参数要求传入模型实例对象,你的代码直接传入了主键整数pk,没有提前从数据库查询得到待更新的Test1实例,会导致ModelForm逻辑异常,大概率会创建新的实例而非更新目标实例。- 更新操作必须将用户提交的POST数据作为第一个参数传给ModelForm,你的代码完全没有传入
request.POST,表单无法获取用户提交的字段值,is_valid()永远返回False,原有逻辑根本无法正常执行更新。
- 隐含的字段覆盖风险
两个表单的fields配置都包含了data字段,如果两次更新操作都修改了data字段,会出现相互覆盖的问题。 - 前端表单提交异常
如果你的页面中同时放置了两个表单,没有做提交隔离,可能出现提交一个表单时携带了另一个表单的外键字段参数的情况,导致非目标字段被写入。
修复方案
第一步:修正视图层核心逻辑
补充请求方法判断、实例查询、POST数据传入逻辑,同时在save时指定更新字段,从底层避免非目标字段被修改:
from django.shortcuts import get_object_or_404 from django.views.decorators.http import require_POST # 修正后的Test1表单更新视图 @require_POST def Testing(request, pk): # 先查询得到待更新的实例 test_instance = get_object_or_404(Test1, pk=pk) # 必须传入request.POST作为第一个参数,再传instance form = Test1ModelForm(request.POST, instance=test_instance) if form.is_valid(): # 指定update_fields明确只更新目标字段,彻底避免其他字段被修改 form.save(update_fields=['a_names', 'data', 'recordname']) # 修正后的Test2表单更新视图 @require_POST def Testing1(request, pk): test_instance = get_object_or_404(Test1, pk=pk) form = Test2ModelForm(request.POST, instance=test_instance) if form.is_valid(): form.save(update_fields=['b_names', 'data', 'recordname2'])
第二步:修正模型类命名规范
你原有代码中模型类定义为小写的test,但表单中关联的model是Test1,需要统一修改模型类名为大驼峰格式,避免关联错误:
# models.py修正后 from django.db import models from django.contrib.auth.models import User class Test1(models.Model): data = models.CharField(max_length=25, null=True) recordname = models.CharField(max_length=25, null=True) recordname2 = models.CharField(max_length=25, null=True) a_names = models.ForeignKey(User, related_name='a_names', on_delete=models.DO_NOTHING, blank=True, null=True) b_names = models.ForeignKey(User, related_name='b_names', on_delete=models.DO_NOTHING, blank=True, null=True)
第三步:检查前端表单
确认两个表单是独立的<form>标签,不存在嵌套,提交时不会携带对方的外键字段参数。
内容的提问来源于stack exchange,提问作者Renjith Rajan
相关产品推荐
相关产品推荐

