Django模型字段根据相关实例自动更新

2024-09-28 05:19:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一个解决方案,能够根据相关的模型实例自动更新模型实例。在

看起来很简单,我到处都找过。我不熟悉这个问题,所以让我知道我问的问题不正确,或者思考问题的方式不对。在

我需要每月捐款帐户自动更新到过去30天内所有相关捐赠的总额。同样地,年度捐赠和终身捐赠也是如此。在

我也需要帐户已订阅如果要切换为真

  • 每月捐赠额>;=20,或
  • 每年捐赠额>;=200或
  • 终身捐赠额>;=10000

如果不符合要求,则返回False。在

class Account(models.Model):
    ...
    is_subscribed = models.BooleanField(
        default=False
    )
    monthly_donations = models.PositiveIntegerField(
        default=0
    )
    yearly_donations = models.PositiveIntegerField(
        default=0
    )
    lifetime_donations = models.PositiveIntegerField(
        default=0
    )


class Donation(models.Model):
    related_account = models.ForeignKey(
        Account,
        on_delete=models.CASCADE,
        related_name='donation'
    )
    amount = models.IntegerField()
    date = models.DateField()

信号是解决办法吗?不过,我不希望总数只在新捐款被保存时才更新。我需要根据捐赠日期每天更新。在


Tags: 实例模型gtfalsedefaultmodelmodels帐户
1条回答
网友
1楼 · 发布于 2024-09-28 05:19:11

信号不能百分之百地解决你的问题。因为monthly_donations和{}依赖于当前日期来给出正确的答案。在

当代码的多个部分对同一事件感兴趣时,信号通常是一个很好的解决方案(在您的例子中,只有Account实例对新的Donation对象感兴趣)。另外,当您不能直接访问代码时(例如,第三方应用程序,或者像User或{}这样的内置模型,您无法对其进行修改)。在

在您的例子中,您可以访问Donation模型,因此您可以重写save()方法:

class Donation(models.Model):
    # db fields ...

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)  # call the actual save method
        update_account_totals()        # execute this code every time the model is saved

但是,正如您已经提到的,您不希望仅在创建新的捐赠时才更新此信息。在

实际上,您当前存储在Account模型中的所有信息都可以动态计算。使用更高级的QuerySet表达式,我们可以直接在数据库中完成所有工作。即使我们每次都要计算它,它也可以很快。特别是如果你缓存结果。在

这种查询称为aggregation。我将使用annotate()函数为您的用例写一个例子。annotate()函数是一个特殊的函数,它根据我们定义的标准为结果集的每个实例“添加额外的字段”。在

通常,我们用annotate()添加的字段是某事物的,或者计数,或者平均值。在您的例子中,我们可以列出所有Account对象,并且对于每个对象,我们可以用每月捐赠、每年捐赠和所有时间捐赠的总和来注释。我们甚至可以使用case/when查询来使用这个计算字段来检查帐户是否是订户。在

它比我们一直使用的诸如filter()all()之类的琐碎的查询集要复杂一点,但是我花时间把它写下来,并给出一些可能对您有帮助的注释。在

PS: The example below uses the new filtering on annotations introduced on Django 2.0

实施:

^{pr2}$

用法:

# then in your code you can use those calculated fields just like you would if it was a regular database field
for account in accounts:
    print(account.monthly)
    print(account.yearly)
    print(account.all_time)
    print(account.subscriber_status)

这将是一个最佳解决方案。这样可以确保数据始终是最新的。另一个解决方案是像您一样保留数据库字段,并在服务器上创建一些cron jobs,这样它们就可以每天更新您的所有帐户,Account字段将作为计算字段的“缓存”。在

{cron>然后可以用cdcron>中提到的方法组合起来。在

相关问题 更多 >

    热门问题