Django 信号循环

Django Signal Loop

谁能帮我解决这个问题。我创建了一个包含两个模型的 django-app。 一种模型是钱包模型,另一种是交易模型。每笔交易都连接到 models.ForeignKey 的钱包。我还创建了两个信号,一个用于在进行交易时更新电子钱包中的加密货币余额(例如 BTC、ETH),另一个我想更新的信号 Total_Balance(所有其他余额都转换为美元) .在这里我遇到了一个问题,因为我的信号是 POST_SAVE 并且其中有一个 save() 方法会导致无限循环。我想如果我在我的第一个信号中做一整件事它会起作用但将来我想添加新模型也将连接到钱包并且它会弹出我的 total_balance,因此我需要相同的第三个信号中的逻辑,我最终会在两个信号中得到相同的代码。

我知道我的描述有点乱。这里有一些代码可以帮助理解它。

我的模特:

class Wallet(models.Model):
    name = models.CharField(max_length=50)
    total_balance = models.IntegerField(blank=True)
    btc_balance = models.DecimalField(max_digits=15, decimal_places=8)
    xrp_balance = models.DecimalField(max_digits=15, decimal_places=8)
    eth_balance = models.DecimalField(max_digits=15, decimal_places=8)

class Transaction(models.Model):
    wallet = models.ForeignKey(Wallet, on_delete=models.CASCADE)
    currency_paid = models.CharField(choices=CURRENCY, max_length=3)
    amount_paid = models.DecimalField(max_digits=15, decimal_places=8)
    currency_recived = models.CharField(choices=CURRENCY, max_length=3)
    amount_recived = models.DecimalField(max_digits=15, decimal_places=8)

我的信号:

@receiver(post_save, sender=Transaction)
def create_transaction(sender, instance, created, **kwargs):
    if created:
        wallet = Wallet.objects.get(name = instance.wallet)

        currency_paid = instance.currency_paid
        currency_recived = instance.currency_recived
        amount_paid = instance.amount_paid
        amount_recived = instance.amount_recived

        # SUBSTRACK BALANCE
        if(currency_paid == 'BTC'):
            wallet.btc_balance -= amount_paid
            ...

        # ADDS BALANCE
        if(currency_recived == 'BTC'):
            wallet.btc_balance += amount_recived
            ...

        wallet.save()


@receiver(post_save, sender=Wallet)
def total_balance_update(sender, instance, created, **kwargs):
    if created == False:
        btc_price = cryptocompare.get_price('BTC',curr='USD')['BTC']['USD']
        xrp_price = cryptocompare.get_price('XRP',curr='USD')['XRP']['USD']
        ...


        btc_balance = float(instance.btc_balance)
        xrp_balance = float(instance.xrp_balance)
        ...
        
        total_balance = instance.total_balance

        total_balance = round(btc_balance * btc_price) + round(xrp_balance * xrp_balance) + round(eth_balance * eth_balance)

        instance.save()

您的 Walletpost_save 执行 instance.save(),这意味着如果您 .save() 您的 Wallet,它将触发 [= Wallet 上的 10=] 信号将再次保存钱包,因此每次信号 运行s 它都会再次保存钱包并触发信号。

据我所知,您不需要使用 post_save 信号,因为您似乎没有使用仅在 对象之后可用的任何东西已保存。您可以使用 pre_save 信号,该信号将 运行 将对象保存到数据库之前:

from django.db.models.signals import <b>pre_save</b>

@receiver(<b>pre_save</b>, sender=Wallet)
def total_balance_update(sender, instance, **kwargs):
    if instance.pk is not None:
        btc_price = cryptocompare.get_price('BTC',curr='USD')['BTC']['USD']
        xrp_price = cryptocompare.get_price('XRP',curr='USD')['XRP']['USD']
        ...


        btc_balance = float(instance.btc_balance)
        xrp_balance = float(instance.xrp_balance)
        ...

        instance.total_balance = round(btc_balance * btc_price) + round(xrp_balance * xrp_balance) + round(eth_balance * eth_balance)
        # <i>no</i> instance.save()

因此我们不需要保存 instance 因为在 运行 发出信号后,Django 将立即在数据库中启动 creating/updating 记录。