Django Forms多外键技术问询:关联三独立模型的第四模型表单实现
实现关联多外键的Django表单方案
嘿,我来帮你搞定这个多外键关联的Django表单问题!首先得把你没写完的第四个模型补全(我假设它叫MedicalRecord,用来关联另外三个检查模型),代码大概是这样:
class MedicalRecord(models.Model): pre_check = models.ForeignKey(PreCheck, on_delete=models.CASCADE) main_check = models.ForeignKey(MainCheck, on_delete=models.CASCADE) post_check = models.ForeignKey(PostCheck, on_delete=models.CASCADE)
接下来分两种最常见的场景给你讲具体实现:
场景1:选择已有的检查记录关联
如果你的需求是让用户从已经创建好的PreCheck、MainCheck、PostCheck记录里选对应的项,那这个最简单,直接用Django的ModelForm就能搞定:
编写表单类
在你的forms.py里定义:
from django import forms from .models import MedicalRecord class MedicalRecordForm(forms.ModelForm): class Meta: model = MedicalRecord fields = ['pre_check', 'main_check', 'post_check']
Django会自动把每个外键字段渲染成下拉选择框,里面是对应模型的所有已存实例。
视图里的逻辑
from django.shortcuts import render, redirect from .forms import MedicalRecordForm def create_medical_record(request): if request.method == 'POST': form = MedicalRecordForm(request.POST) if form.is_valid(): form.save() return redirect('record_list') # 替换成你的记录列表页URL名称 else: form = MedicalRecordForm() return render(request, 'create_record.html', {'form': form})
模板渲染
在create_record.html里直接渲染表单就行:
<form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">保存记录</button> </form>
场景2:在同一个表单里创建新的检查记录并关联
如果需要用户在填写主记录的同时,直接创建对应的PreCheck、MainCheck、PostCheck新记录,那就要用组合表单的方式,手动处理每个子表单的保存:
先写各个子表单
from django import forms from .models import PreCheck, MainCheck, PostCheck class PreCheckForm(forms.ModelForm): class Meta: model = PreCheck fields = ['name', 'is_insured'] # time_in是auto_now_add,自动生成不用用户填 class MainCheckForm(forms.ModelForm): class Meta: model = MainCheck fields = ['height', 'weight'] class PostCheckForm(forms.ModelForm): class Meta: model = PostCheck fields = ['sickness', 'medication']
视图里处理多表单提交
这里要注意给每个子表单加prefix,避免字段名冲突(虽然你的模型里没有重名字段,但加前缀是个好习惯):
from django.shortcuts import render, redirect from .models import MedicalRecord from .forms import PreCheckForm, MainCheckForm, PostCheckForm def create_combined_record(request): if request.method == 'POST': # 用前缀区分不同表单 pre_form = PreCheckForm(request.POST, prefix='pre') main_form = MainCheckForm(request.POST, prefix='main') post_form = PostCheckForm(request.POST, prefix='post') # 验证所有表单都有效 if all([pre_form.is_valid(), main_form.is_valid(), post_form.is_valid()]): # 先保存三个检查记录 pre_check = pre_form.save() main_check = main_form.save() post_check = post_form.save() # 再创建关联的主记录 MedicalRecord.objects.create( pre_check=pre_check, main_check=main_check, post_check=post_check ) return redirect('record_list') else: pre_form = PreCheckForm(prefix='pre') main_form = MainCheckForm(prefix='main') post_form = PostCheckForm(prefix='post') context = { 'pre_form': pre_form, 'main_form': main_form, 'post_form': post_form } return render(request, 'create_combined_record.html', context)
模板里分别渲染子表单
<form method="post"> {% csrf_token %} <h3>预检信息</h3> {{ pre_form.as_p }} <h3>主检信息</h3> {{ main_form.as_p }} <h3>复检信息</h3> {{ post_form.as_p }} <button type="submit">保存全部记录</button> </form>
一些小提示
time_in字段设置了auto_now_add=True,所以不用在表单里显示,Django会自动把它设为记录创建的时间- 如果需要自定义字段样式,比如把身高的输入框改成带单位的,可以在表单类里重写字段,添加
widget属性 - 如果你的模型需要更复杂的关联逻辑,比如外键允许为空,可以在模型里加
null=True, blank=True,表单里也会自动适配
内容的提问来源于stack exchange,提问作者Geoffrey Nyaga
相关产品推荐
相关产品推荐

