Reputation: 18735
In my project, user can set for each of their items schedule for action. This action can be done for example once a week at 1am, every day at 2am or every Monday and Wednesday at 3pm, 6pm and 9am. So the form could look like:
To spare resources, the minimal time is hour so I can run celery task which every hour checks all schedules and find out if it have to do an action now.
I'm trying to figure out what is the best way to store such schedule in the database and how to make such a model.
The first thing I was going to do was to store something like celery cron tab for each product in string format - 'x x x x x'
- for example "hour='3,17,22', day_of_week='thu,fri'"
. But I think that it's bad because I would have to parse each string each hour which is very time-consuming.
Finally I did model with 7 columns - days and 24 columns hours. There are two problems - it isn't probably the best way to store such schedule and the second thing is that every (True) day would have set the same hours which I don't want.
MODEL SCHEDULER - every product has it's own object
class Scheduler(models.Model):
monday = models.BooleanField(default=False)
tuesday = models.BooleanField(default=False)
wednesday = models.BooleanField(default=False)
thursday = models.BooleanField(default=False)
friday = models.BooleanField(default=False)
saturday = models.BooleanField(default=False)
sunday = models.BooleanField(default=False)
hour_1 = models.BooleanField(default=False)
hour_2 = models.BooleanField(default=False)
hour_3 = models.BooleanField(default=False)
hour_4 = models.BooleanField(default=False)
hour_5 = models.BooleanField(default=False)
hour_6 = models.BooleanField(default=False)
hour_7 = models.BooleanField(default=False)
hour_8 = models.BooleanField(default=False)
hour_9 = models.BooleanField(default=False)
hour_10 = models.BooleanField(default=False)
hour_11 = models.BooleanField(default=False)
hour_12 = models.BooleanField(default=False)
hour_13 = models.BooleanField(default=False)
hour_14 = models.BooleanField(default=False)
hour_15 = models.BooleanField(default=False)
hour_16 = models.BooleanField(default=False)
hour_17 = models.BooleanField(default=False)
hour_18 = models.BooleanField(default=False)
hour_19 = models.BooleanField(default=False)
hour_20 = models.BooleanField(default=False)
hour_21 = models.BooleanField(default=False)
hour_22 = models.BooleanField(default=False)
hour_23 = models.BooleanField(default=False)
hour_24 = models.BooleanField(default=False)
TASK which will be called every hour
@app.task()
def check_for_actions():
day = datetime.today().weekday()
hour = datetime.now().hour
# get all schedulers for this day
if day==0:
scheduled_this_day = models.Scheduler.objects.filter(monday=True)
elif day==1:
scheduled_this_day = models.Scheduler.objects.filter(tuesday=True)
elif day==1:
scheduled_this_day = models.Scheduler.objects.filter(wednesday=True)
elif day==1:
scheduled_this_day = models.Scheduler.objects.filter(thursday=True)
elif day==1:
scheduled_this_day = models.Scheduler.objects.filter(friday=True)
elif day==1:
scheduled_this_day = models.Scheduler.objects.filter(saturday=True)
elif day==1:
scheduled_this_day = models.Scheduler.objects.filter(sunday=True)
#filter schedulers for this hour
if hour==1:
scheduled_this_hour = scheduled_this_day.filter(hour_1=True)
elif hour==2:
...
for product in [x.product for x in scheduled_this_hour]:
do_action(product)
As you can see there are two problems. This model can't set different hours for different days and the way of storing such data in Scheduler isn't probably the best according to performance. Do you know how to store such data in model better?
Upvotes: 2
Views: 2685
Reputation: 2454
Why not use one Integer field for the hour, and one CharField with choices for the day of week?
from django.core.validators import MaxValueValidator
class Scheduler(models.Model):
day_of_week = models.CharField(default='Monday',
choices=(('monday', 'Monday'), ('tuesday', 'Tuesday')...))
hour = models.PositiveSmallIntegerField(validators=[MaxValueValidator(24)])
For celery:
# I prefer arrow for formatting dates/times
import arrow
@app.task()
def check_for_actions():
weekday = arrow.utcnow().format('dddd') # Monday, Tuesday, etc
hour = datetime.now().hour
scheduled = models.Scheduler.objects.filter(day_of_week=weekday).filter(hour=hour)
As for
This model can't set different hours for different days
this model can't, but it can have a relationship to whatever you're scheduling.
class Scheduler(models.Model):
thing_to_schedule = models.ForeignKey('ThingToSchedule')
day_of_week = models.CharField(default='Monday',
choices=(('monday', 'Monday'), ('tuesday', 'Tuesday')...))
hour = models.PositiveSmallIntegerField(validators=[MaxValueValidator(24)])
Then ThingToSchedule
has a Schedule set of all the times it needs to be run.
schedules = ThingToSchedule.schedule_set.all()
<Monday at 3>, <Tuesday at 6>
Upvotes: 4