Django:如何将Temporaryresponse的M2M关系及所有字段复制到Completedresponse
解决Django模型字段批量复制与多对多字段同步问题
嘿,我来帮你搞定这两个头疼的问题!先解决批量复制字段的重复劳动,再搞定多对多字段同步的问题。
一、批量复制所有字段(替代手动逐个赋值)
手动逐个字段赋值不仅麻烦,还容易漏字段。我们可以利用Django模型的特性来批量处理,这里给你两种靠谱的方式:
方式1:利用模型元数据(更安全,适配字段变更)
这种方式会自动匹配两个模型的共同字段,排除掉Django自动生成的字段(比如id、_state)和多对多字段(因为多对多字段不在_meta.fields里):
def vr(request, pk): finalresponse = get_object_or_404(Temporaryresponse, pk=pk) instance = Temporaryresponse.objects.get(pk=pk) if request.method == "POST": form = VotingresponseForm(request.POST, instance=instance) if form.is_valid(): votingresponse = form.save() # 获取两个模型的共同字段(排除自动字段和多对多) common_field_names = [ field.name for field in Temporaryresponse._meta.fields if field.name not in ['id', '_state'] and field.name in [f.name for f in Completedresponse._meta.fields] ] # 批量赋值创建Completedresponse实例 completed_response = Completedresponse() for field_name in common_field_names: setattr(completed_response, field_name, getattr(votingresponse, field_name)) completed_response.save() # 处理多对多字段(后面讲) completed_response.race.set(votingresponse.race.all()) return redirect('completed')
方式2:利用对象字典(更简洁)
直接从votingresponse.__dict__中提取字段值,过滤掉不需要的内部键(比如Django的_state、多对多缓存键_race_cache):
def vr(request, pk): finalresponse = get_object_or_404(Temporaryresponse, pk=pk) instance = Temporaryresponse.objects.get(pk=pk) if request.method == "POST": form = VotingresponseForm(request.POST, instance=instance) if form.is_valid(): votingresponse = form.save() # 过滤掉不需要的字段 instance_data = { key: value for key, value in votingresponse.__dict__.items() if key not in ['id', '_state', '_race_cache'] } # 直接用字典解包创建实例 completed_response = Completedresponse(**instance_data) completed_response.save() # 处理多对多字段 completed_response.race.set(votingresponse.race.all()) return redirect('completed')
二、多对多字段race的同步问题
你之前用add方法没成功,是因为votingresponse.race是一个RelatedManager,直接传整个QuerySet给add会报错。正确的做法有两种:
方法1:使用set()方法(推荐)
set()可以直接接收一个QuerySet,一次性设置所有关联对象:
# 必须先保存completed_response,再处理多对多 completed_response.save() completed_response.race.set(votingresponse.race.all())
方法2:使用add()并解包QuerySet
如果一定要用add,需要把QuerySet里的对象逐个传进去,用*解包:
completed_response.save() completed_response.race.add(*votingresponse.race.all())
最终整合后的代码
把上面的方法整合起来,最终的视图函数会变成这样:
def vr(request, pk): finalresponse = get_object_or_404(Temporaryresponse, pk=pk) instance = Temporaryresponse.objects.get(pk=pk) if request.method == "POST": form = VotingresponseForm(request.POST, instance=instance) if form.is_valid(): votingresponse = form.save() # 批量复制字段(用方式2的简洁版) instance_data = { key: value for key, value in votingresponse.__dict__.items() if key not in ['id', '_state', '_race_cache'] } completed_response = Completedresponse(**instance_data) completed_response.save() # 同步多对多字段race completed_response.race.set(votingresponse.race.all()) return redirect('completed')
注意:如果你的Completedresponse模型有必填字段不在Temporaryresponse里,需要额外处理这些字段的赋值哦!
内容的提问来源于stack exchange,提问作者jm2288
相关产品推荐
相关产品推荐

