Milano
Milano

Reputation: 18735

Storing weekly/daily scheduling in Django database

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:

enter image description here

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

Answers (1)

Jens Astrup
Jens Astrup

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

Related Questions