Django post_save信号无法检测父类多对多字段pricing_tier值如何解决
问题根源
该问题是Django模型保存的固有机制导致的:多对多字段的关联数据保存动作,发生在模型主实例的post_save信号触发之后。你在post_save信号里查询关联的pricing_tier的时候,多对多的关联记录还没写入中间表,所以永远会拿到空查询集。
方案1:使用m2m_changed信号(推荐)
m2m_changed是专门用来监听多对多字段变更的信号,会在多对多关联数据修改时触发,你可以监听pricing_tier字段的关联新增动作,配合实例是否是新建的状态判断即可。
代码示例:
from django.db.models.signals import m2m_changed from django.dispatch import receiver @receiver(m2m_changed, sender=Blog.pricing_tier.through) def blog_notify_receiver(sender, instance, action, *args, **kwargs): # 只监听多对多关联新增的动作,且仅针对Blog实例触发 if action == "post_add" and isinstance(instance, Blog): if instance.pricing_tier.filter(slug='free-trial').exists(): try: BlogNotification.objects.create() except: pass
注意这里的sender要指定为多对多字段的自动生成中间表,也就是Blog.pricing_tier.through。
方案2:使用事务回调延迟执行检测
如果你的业务逻辑必须和post_save绑定,可以用transaction.on_commit让检测逻辑延迟到当前数据库事务完全提交后再执行,这时候包括多对多在内的所有数据都已经落库。
代码示例:
from django.db import transaction from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=Blog) def blog_notify_receiver(sender, instance, created, *args, **kwargs): if not created: return # 事务完全提交后再执行多对多字段检测 def check_pricing_after_commit(): if instance.pricing_tier.filter(slug='free-trial').exists(): try: BlogNotification.objects.create() except: pass transaction.on_commit(check_pricing_after_commit)
这个方案的好处是不需要额外判断多对多的动作类型,适合逻辑比较简单的场景。
内容的提问来源于stack exchange,提问作者Biju
相关产品推荐
相关产品推荐

