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?
Is there any reason you wouldn't just calculate the boolean field in your business logic? i.e. when you receive a request related to that race, simply check the times and assess whether or not the race is active (for display, analysis), etc.
I'm assuming you won't have high load (one reason for pre-processing) like this.
Assuming the following scenarios -
active
isfalse
it will never betrue
again.There are numerous ways you can set that true automatically depending on your need -
If you need only when using the object, you can use a property -
you can also put it in the init -
But this does not give you the option to perform query, because value is calculated after object is loaded in memory.
If you want to perform query, so we need to update the value in the database and save it. Assuming that when the race ends, you update the date in the overridden save method -
So when you save the object after the race ends, it will update the flag.
But if it is not possible for you to update the race when it ends and you need them to be calculated automatically you could use a scheduler. Like
Celery
as @rahul suggested to update periodically. But for this option, you have to accept the fact that, theactive
flag will not be updated at the exact time of the game ends. It will depend on how frequently you run the scheduler.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 theis_active
flag of therace_object
toFalse
after the current date is greater than theend_time
of therace_object
.This task will be executed by
Celery
only if the current time is greater than the race object'send_time
.Step-2: Call this celery task using
eta
argumentAfter 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 theend_time
of therace_object
.We will call the task using
apply_async()
and pass theeta
argument as theend_time
of therace_object
.As per Celery docs,
This checking of
self.pk
withNone
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 (eitherINSERT
orUPDATE
) 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 theend_time
of the race. After theend_time
has elapsed, Celery will execute that task.It sounds to me that your "active" field should be a method instead like this:
If you are using Django 1.7+ or South with older versions, this is a trivial change and will normalise your database too, unless the "active" field was intentionally created.
You can override the predefined save method like this: