如何使用多对多关联对象数据自动填充Django模型表单字段
错误原因
- 直接报错
name 'serviceItemStats' is not defined是因为你在JobEntry的save方法中误用了字段名(小写开头的serviceItemStats是多对多字段名,不是模型类名),且调用objects.all()会查询全表数据,不是当前实例关联的服务项。 - 原生逻辑存在本质缺陷:多对多关联数据必须在
JobEntry实例保存生成主键后才能写入数据库,你在模型save方法中执行计算时,还没有拿到表单提交的选中服务项,永远算不出正确结果。 - 其他细节错误:未使用求和聚合函数
Sum、表单部件配置的字段名大小写不匹配、视图form_valid方法的super调用参数错误。
修复步骤
1. 修正models.py
删除原save方法中的错误计算逻辑,无需在模型层处理该需求:
class JobEntry(models.Model): # 原有字段保持不变 def save(self, *args, **kwargs): super().save(*args, **kwargs) # 其余原有方法保持不变
2. 修正forms.py
修改部件配置的字段名,和模型字段名保持大小写一致:
class NewJobEntryForm(ModelForm): class Meta: model = JobEntry fields = ['vehicle', 'customer', 'job_date', 'job_checked_in', 'job_priority', 'job_comments', 'job_parts_instock', 'serviceItemStats'] widgets = { 'job_date' : forms.DateInput(format=('%m/%d/%Y'), attrs={'class':'form-control', 'placeholder':'Select a date', 'type':'date'}), 'serviceItemStats' : forms.CheckboxSelectMultiple(), # 此处首字母改为小写,匹配字段名 'job_priority' : forms.RadioSelect(choices=priorityOptions), }
3. 修正views.py
首先导入聚合函数:from django.db.models import Sum
将FormView替换为更适配模型创建场景的CreateView,重写form_valid方法处理计算逻辑:
class JobCreateView(CreateView): template_name = "jobs/jobentry_form.html" form_class = NewJobEntryForm success_url = reverse_lazy("jobs:job_list") def form_valid(self, form): # 先保存实例不提交,获取JobEntry对象 job_entry = form.save(commit=False) # 保存实例生成主键,为后续写入多对多关联做准备 job_entry.save() # 写入表单提交的多对多选中项 form.save_m2m() # 聚合计算所有关联服务项的预估时长总和 total_estimate = job_entry.serviceItemStats.aggregate( total=Sum('service_stats_estimate_duration') )['total'] or 0 # 赋值后二次保存 job_entry.job_time_estimation = total_estimate job_entry.save() return super().form_valid(form)
补充说明
如果后续需要支持编辑JobEntry时同步更新预估时长,在对应的更新视图的保存逻辑中加入同样的聚合计算步骤即可。
内容的提问来源于stack exchange,提问作者Arnas
相关产品推荐
相关产品推荐

