一对多(外键)关系下m2m_changed信号的替代方案咨询
问题
我有模型A(作为模型B的外键)和模型C。需求是:当在A的Admin内联中修改B后,获取该A关联的所有B实例的quantity总和,以此更新模型C。
具体步骤:
- 当保存A1的Admin表单时,B1、B2、B3均以A1作为
fk_a; - 等待所有B实例完成
save()后,计算它们的quantity总和,并用该值更新对应的C1、C2、C3。
相关模型代码:
from django.db import models class A(models.Model): name = models.CharField(max_length=20) class B(models.Model): quantity = models.IntegerField() fk_a = models.ForeignKey(A, on_delete=models.CASCADE) def save(self): sum_of_similar_b = B.objects.filter(fk_a=self.fk_a) similar_c = C.objects.filter(fk_a=self.fk_a) update_model_c(sum_of_simlar_b, similar_c)
我尝试过post_save信号,但它在外键更新前就被触发;也试过重写A的save()方法,效果相同;尝试无through表的m2m_changed信号,但未触发。
解决方案
方法1:重写Admin的save_formset方法
在A的Admin类中重写save_formset,这个方法会在所有内联的B实例保存完成后执行,完全匹配需求场景:
from django.contrib import admin from .models import A, B, C class BInline(admin.TabularInline): model = B class AAdmin(admin.ModelAdmin): inlines = [BInline] def save_formset(self, request, form, formset, change): # 先保存所有内联的B实例 formset.save() # 获取当前操作的A实例 a_instance = form.instance # 计算该A关联的所有B的quantity总和 total_quantity = B.objects.filter(fk_a=a_instance).aggregate(total=models.Sum('quantity'))['total'] or 0 # 批量更新对应的C实例 C.objects.filter(fk_a=a_instance).update(total_quantity=total_quantity) admin.site.register(A, AAdmin)
方法2:使用transaction.on_commit延迟计算
如果不想修改Admin类结构,可以在post_save信号中通过事务提交后的回调,确保所有B实例都已完成保存:
from django.db.models.signals import post_save from django.db import transaction from django.dispatch import receiver from .models import B, C @receiver(post_save, sender=B) def update_c_after_b_save(sender, instance, **kwargs): def update_c_task(): a_instance = instance.fk_a total_quantity = B.objects.filter(fk_a=a_instance).aggregate(total=models.Sum('quantity'))['total'] or 0 C.objects.filter(fk_a=a_instance).update(total_quantity=total_quantity) # 等待当前事务提交后执行,避免计算时部分B实例未保存 transaction.on_commit(update_c_task)
关键注意点
- 不要在B的
save()方法中直接计算总和,Admin内联保存会触发多次B的save,导致重复计算、效率低下。 transaction.on_commit能确保所有数据库操作完成后再执行计算,彻底解决“部分实例未保存”的问题。
内容的提问来源于stack exchange,提问作者Hazem Elmahy
相关产品推荐
相关产品推荐

