【问题标题】:How can I update a model field based on updating another model's field using Signals?如何根据使用信号更新另一个模型的字段来更新模型字段?
【发布时间】:2016-01-31 06:02:35
【问题描述】:

我正在尝试将所有 total 值添加到 Transaction 模型中,并将它们放入 Sale 模型的第一个实例 (pk=1) gross_total 字段中。这是我的代码。

models.py

class Sale(models.Model):
    gross_total = models.FloatField()

    def __unicode__(self):
        return str(self.gross_total)

class Transaction(models.Model):
    sale = models.ForeignKey('Sale')
    price = models.FloatField()
    quantity = models.IntegerField()
    total = models.FloatField(blank=True, null=True)

    def save(self):
        self.total = self.price * self.quantity
        return super(Transaction, self).save()

    def __unicode__(self):
        return str(self.total)

signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.db.models import Sum

from .models import Transaction, Sale

@receiver(post_save, sender=Transaction)
def update_sale(sender, **kwargs):
    sale = Sale.objects.get(pk=1)
    sale.gross_total = Transaction.objects.all().aggregate(Sum('total'))['total__sum']
    sale.save()

我是使用 Django 信号的新手。我做错了什么?如果我保存Transaction 模型的实例,Sale 模型数据不会更新!

【问题讨论】:

  • 您是否按照“这段代码应该放在哪里?”文档中的框docs.djangoproject.com/en/1.9/topics/signals/… ?
  • @Nikita 我没有那样做。我已经阅读了文档中的信号章节,但对我来说不是很清楚。你能在这方面提供帮助吗?
  • @Nikita 好的,我可以从另一个博客复制代码,但我不知道它是如何工作的!你能给我推荐一个简单的阅读材料吗?
  • 不幸的是,我对易读材料一无所知,我同意 Django 文档的部分内容从清晰的解释到“我在读什么”:)。但是我试图在其他答案中解释一些。

标签: django signals


【解决方案1】:

会发生什么……

当您在signals.py 中编写代码时,它是有效代码,但它永远不会运行,直到该模块被直接执行(虽然在这种情况下不是预期用途)或被导入。因此必须将其导入某处才能运行代码并将处理函数注册到相应的信号。

当您的 Django 项目运行时,Django 会根据您在 settings.py 中声明的应用程序创建应用程序注册表。在创建注册表时,它会导入在settings.py 中声明的每个包和模块,并在此过程中调用几个预定义函数,包括每个AppConfig 中的ready()

在 Python 中导入包时,特殊文件 __init__.py 中的代码由 Python 内部自动执行,通常它允许为包定义特殊行为和属性。

所以基本上,这会导致:

  1. Django 项目启动。

  2. Django 读取 settings.py 并发现您的应用是已声明的应用之一。

  3. Django 导入您的 App 包,运行 __init__.py 内的代码并指定 default_app_config。现在 Dgango 知道了。

  4. 当所有应用程序的处理完成后,Django 会为前面步骤中找到的每个 AppConfig 调用 ready() 函数。

  5. MyAppConfig 中的ready() 运行并导入您的signals.py 模块。

  6. 在此导入期间,signals.py 中的代码被执行:您的 update_sale 函数被创建,@receiver 装饰器被作为参数执行。

  7. receiver 装饰器代码在执行时注册 update_sale 函数,该函数将在 Transaction 模型类发出的 post_save 信号上运行。

【讨论】:

    【解决方案2】:

    我对我的应用进行了以下更改以使其正常工作。

    __init__.py

    default_app_config = 'alpha.apps.MyAppConfig'
    

    现在在我的应用程序中创建一个 apps.py。

    apps.py

    from django.apps import AppConfig
    
    class MyAppConfig(AppConfig):
        name = 'alpha'
        verbose_name = 'Alpha'
    
        def ready(self):
            import alpha.signals
    

    我不知道这一切是如何运作的,哈哈。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 2020-08-08
      • 1970-01-01
      • 2020-08-13
      • 2014-12-25
      • 1970-01-01
      • 2022-10-24
      相关资源
      最近更新 更多