You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django pre_save信号created参数取值异常问题求助

Django pre_save信号中created参数异常的解决方法

问题背景

我在为ProofOfPayment模型通过pre_save信号处理字段逻辑:新记录创建时自动填充参考编号、支付状态;更新时检查支付状态变化并设置过期时间。但后台创建新记录时,created参数被设为False,进入else分支执行sender.objects.get(pk=instance.pk)时触发“ProofOfPayment matching query does not exist”错误。

如果不给created设默认值,会提示“pre_save_for_proof_of_payment() missing 1 required positional argument: 'created'”;设默认值为True,新记录创建时信号逻辑又不触发。原本以为Django会自动根据记录是否为新传入created的布尔值,实际却使用了默认值,请问该如何正确设置created参数来区分新/旧记录?

原因分析

Django的pre_save信号会自动传递created参数判断实例状态,但手动给created设置默认值会干扰参数传递逻辑;若函数定义缺失created参数,又会因信号传参不匹配报错。此外,后台admin创建记录时可能出现created参数传递异常,此时通过实例内部属性_state.adding判断状态更可靠。

解决方案

方案1:正确定义信号函数,不设置created默认值

严格匹配pre_save信号的参数传递顺序,不手动给created设置默认值,让Django自动传入正确的布尔值。

方案2:使用instance._state.adding判断实例状态

直接检查实例的_state.adding属性(True表示新实例未保存,False表示已存在实例待更新),该方式不依赖信号传递的created参数,稳定性更强。

修正后的代码

方案1代码(正确接收created参数)

from django.db.models.signals import pre_save
from django.dispatch import receiver
from datetime import datetime, timedelta
from .models import ProofOfPayment, PaymentStatus

@receiver(pre_save, sender=ProofOfPayment)
def pre_save_for_proof_of_payment(sender, instance, created, **kwargs):
    print('created', created)
    if created:
        upload_date = datetime.now().strftime('%Y%m%d%H%M%S')
        instance.reference_number = f'PAYMENT-{upload_date}'
        instance.payment_status = PaymentStatus.objects.get(pk=1)  # Received状态
    else:
        original_instance = sender.objects.get(pk=instance.pk)
        if original_instance.payment_status != instance.payment_status:
            if instance.payment_status.name == 'Completed':
                instance.expiry_date = datetime.now() + timedelta(days=30)

方案2代码(使用_state.adding)

from django.db.models.signals import pre_save
from django.dispatch import receiver
from datetime import datetime, timedelta
from .models import ProofOfPayment, PaymentStatus

@receiver(pre_save, sender=ProofOfPayment)
def pre_save_for_proof_of_payment(sender, instance, **kwargs):
    if instance._state.adding:
        # 新实例逻辑
        upload_date = datetime.now().strftime('%Y%m%d%H%M%S')
        instance.reference_number = f'PAYMENT-{upload_date}'
        instance.payment_status = PaymentStatus.objects.get(pk=1)  # Received状态
    else:
        # 更新实例逻辑
        original_instance = sender.objects.get(pk=instance.pk)
        if original_instance.payment_status != instance.payment_status:
            if instance.payment_status.name == 'Completed':
                instance.expiry_date = datetime.now() + timedelta(days=30)

额外优化建议

  • 更新逻辑中查询原始实例时,若担心性能问题可考虑缓存原始值,多数场景下直接查询可接受。
  • 避免硬编码PaymentStatus.objects.get(pk=1),可改用PaymentStatus.objects.get(name='Received')或定义常量,提升代码可维护性。

内容的提问来源于stack exchange,提问作者Nikko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 23:25:23