如何通过单HTML表单存储Django一对多模型数据并避免医生记录重复
解决Django一对多模型重复创建关联对象的问题
核心问题分析
当前视图每次提交表单都会直接调用Doctor.objects.create()创建新医生记录,完全不检查数据库中是否已存在相同医生,这是重复创建的根本原因。此外还存在文件上传处理错误、性别选项不匹配的问题。
解决方案步骤
1. 用get_or_create避免重复创建医生
Django的get_or_create()方法会先尝试根据指定条件查询对象,不存在则创建,完美解决重复问题。选择手机号作为唯一标识条件(手机号具备唯一性,比姓名更可靠)。
2. 修复文件上传的处理逻辑
文件字段不能通过request.POST.get()获取,必须使用request.FILES.get(),你的表单已设置enctype="multipart/form-data",这部分无需额外修改。
3. 统一性别选项的取值
表单中性别选项值与模型定义的选项不匹配,需要统一两者取值,否则会触发模型验证失败。
4. 数据类型转换
表单提交的年龄、手机号等数值为字符串类型,需转换为整数后再存入模型的IntegerField字段。
修改后的代码
视图代码(views.py)
def requestlanding(request): if request.method == "POST": # 处理患者数据 p_name = request.POST.get("patientName") p_age = int(request.POST.get("age")) p_gender = request.POST.get("gender").capitalize() p_phone = int(request.POST.get("contactPatient")) p_email = request.POST.get("emailPatient") p_wrecommend = request.FILES.get("wrecommend") # 处理医生数据 d_name = request.POST.get("doctorName") d_phone = int(request.POST.get("contactDoctor")) d_specialization = request.POST.get("specialization") # 使用get_or_create避免重复创建医生,以手机号为唯一标识 doctor, created = Doctor.objects.get_or_create( phone=d_phone, defaults={ 'name': d_name, 'specialization': d_specialization } ) # 若需更新已存在医生的信息,可在此添加额外逻辑 # 创建患者并关联到医生 patient = Patient.objects.create( doctor=doctor, name=p_name, email=p_email, phone=p_phone, age=p_age, gender=p_gender, wrecommend=p_wrecommend, ) return redirect("requestlanding") return render(request, "docpatient.html")
表单代码(docpatient.html)
修改性别选项的value,与模型定义保持一致:
<select id="gender" name="gender" required> <option value="Male">Male</option> <option value="Female">Female</option> <option value="Others">Other</option> </select>
模型代码(models.py)
可选:给Doctor的phone字段添加unique=True约束,从数据库层面避免重复手机号的医生:
phone = models.IntegerField( validators=[MinValueValidator(1000000000), MaxValueValidator(9999999999)], blank=False, unique=True )
实现医生关联所有患者的功能
通过反向查询可获取医生的所有患者:
- 默认反向关联名称为模型名小写加
_set,在视图/模板中可使用doctor.patient_set.all() - 若要自定义反向关联名称,可在Patient模型的ForeignKey中添加
related_name参数:
doctor = models.ForeignKey(Doctor, on_delete=models.PROTECT, related_name='patients')
之后即可用doctor.patients.all()获取该医生的所有患者。
内容的提问来源于stack exchange,提问作者Nabin Prasad Dhungana
相关产品推荐
相关产品推荐

