我正在研究赛车活动的django项目,其中数据库中的表有三个字段。
1)布尔字段,用于了解种族是否有效
2)比赛开始时间
3)比赛结束时间
在创建对象时,会指定start_time和end_time。比赛开始时如何将布尔字段的值更改为True 结束时为假?如何安排这些活动?
答案 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}}传递。
ETA(预计到达时间)可让您设定特定日期和 时间是执行任务的最早时间。
保证在指定后的某个时间执行任务 日期和时间,但不一定是在那个确切的时间。
apply_async()
eta
与end_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)
假设以下情况 -
active
false
后true
永远不会再@property
def active(self):
return self.end_date > datetime.datetime.utcnow() //I used local time if you want
。根据您的需要,您可以通过多种方式自动设置 -
如果只在使用对象时才需要,可以使用属性 -
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