Django:如何在同一对象中提到的时间自动更改字段的值?

时间:2015-04-27 18:18:11

标签: python django django-models celery django-celery

我正在研究赛车活动的django项目,其中数据库中的表有三个字段。

1)布尔字段,用于了解种族是否有效

2)比赛开始时间

3)比赛结束时间

在创建对象时,会指定start_time和end_time。比赛开始时如何将布尔字段的值更改为True 结束时为假?如何安排这些活动?

5 个答案:

答案 0 :(得分:15)

要在特定时间后自动更新模型字段,您可以使用Celery tasks

步骤1:创建芹菜任务

我们将首先创建一个名为set_race_as_inactive的芹菜任务,该任务会在当前日期大于{{1}后将is_active的{​​{1}}标记设置为race_object } False

仅当当前时间大于竞赛对象的end_time时,此任务才会由race_object执行。

Celery

步骤2:使用eta参数

调用此芹菜任务

创建芹菜任务end_time后,我们需要调用此芹菜任务。

每当我们将新@app.task def set_race_as_inactive(race_object): """ This celery task sets the 'is_active' flag of the race object to False in the database after the race end time has elapsed. """ race_object.is_active = False # set the race as not active race_object.save() # save the race object 保存到数据库中时,我们都会调用此任务。因此,只要保存新的set_race_as_inactive,就会触发芹菜任务,该任务只会在race_object的{​​{1}}之后执行。

我们将使用race_object调用该任务,并将end_time参数作为race_object的{​​{1}}传递。

根据Celery docs,

  

ETA(预计到达时间)可让您设定特定日期和   时间是执行任务的最早时间。

     

保证在指定后的某个时间执行任务   日期和时间,但不一定是在那个确切的时间。

apply_async()

etaend_time的检查已完成,只有在创建新对象的情况下,才会创建芹菜任务。如果我们不这样做,那么对于每次race_object来电(from my_app.tasks import set_race_as_inactive class RaceModel(models.Model): ... def save(self, *args, **kwargs): .. create_task = False # variable to know if celery task is to be created if self.pk is None: # Check if instance has 'pk' attribute set # Celery Task is to created in case of 'INSERT' create_task = True # set the variable super(RaceModel, self).save(*args, **kwargs) # Call the Django's "real" save() method. if create_task: # check if task is to be created # pass the current instance as 'args' and call the task with 'eta' argument # to execute after the race `end_time` set_race_as_inactive.apply_async(args=[self], eta=self.end_time) # task will be executed after 'race_end_time' self.pk),都会创建一个我们不想要的芹菜任务。这将导致许多不必要的芹菜任务等待执行,并将使我们的芹菜队列超载。

使用Celery的好处None标志的更新将在后台异步自动发生,而无需担心手动更新它们。每次创建一个新的种族对象时,都会触发一个任务,Celery会将其执行推迟到竞赛的.save()。在INSERT过去之后,Celery将执行该任务。

答案 1 :(得分:4)

假设以下情况 -

  1. 您希望与数据库无关
  2. 一旦比赛结束,它永远不会重新开始,所以active falsetrue永远不会再@property def active(self): return self.end_date > datetime.datetime.utcnow() //I used local time if you want
  3. 根据您的需要,您可以通过多种方式自动设置 -

    如果只在使用对象时才需要,可以使用属性 -

    def __init__(self):
        super().__init__()
        self.active = self.end_date > datetime.datetime.utcnow()
    

    你也可以把它放在init -

    def save(self, *args, **kwargs):
        self.active = self.end_date > datetime.datetime.utcnow()
        super().save()
    

    但这并没有为您提供执行查询的选项,因为在内存中加载对象后会计算值。

    如果要执行查询,我们需要更新数据库中的值并保存。假设比赛结束时,您在覆盖的保存方法中更新日期 -

    Celery

    因此,当比赛结束后保存对象时,它将更新标志。

    但是如果你不能在比赛结束时更新比赛并且你需要自动计算它们,你可以使用一个调度程序。像active一样@rahul建议定期更新。但是对于此选项,您必须接受以下事实:setMinimumHeight(Integer)标志不会在游戏结束的确切时间更新。这取决于您运行调度程序的频率。

答案 2 :(得分:1)

听起来我的“主动”字段应该是一种方法,而不是这样:

from django.utils import timezone
class Race(models.Model):
    start = models.DateTimeField()
    end = models.DateTimeField()
    def active(self):
        now = timezone.now()
        if self.start < now and now < self.end:
            return True
        return False

如果您使用的是旧版本的Django 1.7+或South,这是一个微不足道的更改,并且会对您的数据库进行规范化,除非故意创建“活动”字段。

答案 3 :(得分:-1)

你有什么理由不计算业务逻辑中的布尔字段吗?即当您收到与该种族相关的请求时,只需检查时间并评估比赛是否有效(用于展示,分析)等。

我假设您没有像这样的高负荷(预处理的一个原因)。

答案 4 :(得分:-1)

您可以覆盖预定义的保存方法,例如this

ItemPropertiesList