Django OneToOneField关联模型插入记录失败问题排查
Django ItemSettings 插入失败问题排查与修复
问题背景
已定义ItemMaster和ItemSettings一对一关联模型,ItemSettings初始无数据。为每个ItemMaster的物料编号设置“规则”链接,用于添加/编辑对应ItemSettings,要求ItemNumber不以下拉框形式展示,但当前代码无法向ItemSettings插入记录,需排查错误。
现有代码
Models.py
class ItemMaster(models.Model): project_name = models.ForeignKey(ProjectMaster, null=True, on_delete=models.SET_NULL) item_number = models.CharField(max_length=15, unique=True, error_messages={ 'unique': "This Item Number Already Exists!"}) item_type = models.ForeignKey(ItemType, null=True, on_delete=models.SET_NULL) item_description = models.CharField(max_length=255, blank=True, null=True) def __str__(self): return self.item_number class ItemSettings(models.Model): item_number = models.OneToOneField(ItemMaster, on_delete=models.CASCADE) low_at = models.FloatField(default=0) minimum_value = models.FloatField(default=0) maximum_value = models.FloatField(default=0) def __str__(self): return str(self.item_number)
Views.py
def itemsettings_edit(request, pkey): item_master_data = ItemMaster.objects.get(id=pkey) item_no = item_master_data.item_number form = ItemSettingsForm() if request.method == "GET": return render(request, 'masters/edit.html', {'item_no': item_no}) elif request.method == 'POST': try: item_number = request.POST['item_no'] low_at = request.POST['low_at'] minimum_value = request.POST['minimum_value'] maximum_value = request.POST['maximum_value'] form = ItemSettingsForm(request.POST) ItemSettings(item_number=item_number, low_at=low_at, minimum_value=minimum_value, maximum_value=maximum_value).save() messages.SUCCESS(request, 'Data Saved') except Exception as e: messages.SUCCESS(request, 'Data Already Added!!!') return render(request, 'masters/edit.html', {'item_no': item_no, 'form': form})
edit.html
<form action="" enctype="multipart/form-data" method="POST" novalidate> {% csrf_token %} <table> <tr> <td>Item No.</td> <td><input name="item_number" readonly type="text" value="{{ item_no }}"></td> </tr> <tr> <td>Low At</td> <td><input name="low_at" type="text"></td> </tr> <tr> <td>Minimum</td> <td><input name="minimum_value" type="text"></td> </tr> <tr> <td>Maximum</td> <td><input name="maximum_value" type="text"></td> </tr> </table> <div class="card-action"> <button class="btn waves-effect waves-light btn-small" name="action" type="submit">Save </button> <a class="btn grey darken-3 waves-effect waves-light btn-small" href="{% url 'itemMaster_list' %}">Cancel</a> </div> </form>
错误点分析
- POST参数获取错误:模板中Item No的input
name为item_number,但视图里用request.POST['item_no']获取,会触发KeyError直接进入异常分支。 - 关联字段赋值错误:
ItemSettings的item_number是OneToOne关联ItemMaster,必须传入ItemMaster对象或其主键ID,不能直接传字符串类型的物料编号。 - Messages调用错误:Django的messages方法为小写开头,
messages.SUCCESS应为messages.success,否则会报错。 - 未处理编辑场景:若
ItemSettings已存在,直接创建会触发唯一性约束异常,且GET请求未加载已有数据到表单。 - 缺乏数据验证:直接将POST字符串存入FloatField,若输入非数字会报错,且未使用表单验证逻辑。
修复后的代码
Views.py 修正版
from django.contrib import messages def itemsettings_edit(request, pkey): item_master = ItemMaster.objects.get(id=pkey) # 自动处理新增/编辑:存在则获取,不存在则新建 item_settings, created = ItemSettings.objects.get_or_create(item_number=item_master) if request.method == "GET": # 绑定已有数据到表单,实现编辑回显 form = ItemSettingsForm(instance=item_settings) return render(request, 'masters/edit.html', {'item_no': item_master.item_number, 'form': form}) elif request.method == 'POST': form = ItemSettingsForm(request.POST, instance=item_settings) if form.is_valid(): form.save() messages.success(request, '数据保存成功') else: messages.error(request, '输入数据有误,请检查') return render(request, 'masters/edit.html', {'item_no': item_master.item_number, 'form': form})
补充表单类(forms.py)
隐藏item_number字段,避免前端出现下拉框:
from django import forms from .models import ItemSettings class ItemSettingsForm(forms.ModelForm): class Meta: model = ItemSettings fields = ['low_at', 'minimum_value', 'maximum_value']
edit.html 简化版
<form action="" method="POST" novalidate> {% csrf_token %} <table> <tr> <td>Item No.</td> <td><input name="item_number" readonly type="text" value="{{ item_no }}"></td> </tr> {{ form.as_table }} </table> <div class="card-action"> <button class="btn waves-effect waves-light btn-small" type="submit">Save</button> <a class="btn grey darken-3 waves-effect waves-light btn-small" href="{% url 'itemMaster_list' %}">Cancel</a> </div> </form>
关键修复说明
- 用
get_or_create确保每个ItemMaster对应唯一的ItemSettings,同时兼容新增和编辑场景。 - 表单绑定
instance实现数据回显和更新,通过form.is_valid()验证数据,避免类型错误。 - 修正messages调用方式,确保提示正常显示。
- 表单类隐藏
item_number字段,后端直接用视图中获取的ItemMaster对象关联,无需从POST获取,符合需求。
内容的提问来源于stack exchange,提问作者chlorinelemon
相关产品推荐
相关产品推荐

