Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
106 views
in Technique[技术] by (71.8m points)

python - Django: How to automatically change a field's value at the time mentioned in the same object?

I am working on a django project for racing event in which a table in the database has three fields.

1)Boolean field to know whether race is active or not

2)Race start time

3)Race end time

While creating an object of it,the start_time and end_time are specified. How to change the value of boolean field to True when the race starts and
to False when it ends? How to schedule these activities?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To automatically update a model field after a specific time, you can use Celery tasks.

Step-1: Create a Celery Task

We will first create a celery task called set_race_as_inactive which will set the is_active flag of the race_object to False after the current date is greater than the end_time of the race_object.

This task will be executed by Celery only if the current time is greater than the race object's 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 

Step-2: Call this celery task using eta argument

After creating the celery task set_race_as_inactive, we need to call this celery task.

We will call this task whenever we save a new race_object into our database. So, whenever a newrace_object will be saved, a celery task will be fired which will execute only after the end_time of the race_object.

We will call the task using apply_async() and pass the eta argument as the end_time of the race_object.

As per Celery docs,

The ETA (estimated time of arrival) lets you set a specific date and time that is the earliest time at which your task will be executed.

The task is guaranteed to be executed at some time after the specified date and time, but not necessarily at that exact time.

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'

This checking of self.pk with None is done so that only in case of new objects creation, a celery task is created. If we don't do this, then for every .save() call (either INSERT or UPDATE) a celery task will be created which we don't want. This will lead to many unnecessary celery tasks waiting to be executed and will overload our celery queues.

The benefit of using Celery is that updation of the is_active flag will occur automatically in the background asynchronously without you needing to worry about manually updating them. Every time a new race object is created, a task will be fired and Celery will defer its execution until the end_time of the race. After the end_time has elapsed, Celery will execute that task.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...