Search code examples
djangodjango-modelscrondjango-viewspython-datetime

How to repeat django event occurrence period?


I have a model that gets the day and time of week when an event should always occur. Also, the number of days before the event that people will be able to attend.

def validate_only_one(obj):
    model = obj.__class__
    if model.objects.count() > 0 and obj.id != model.objects.get().id:
        raise ValidationError("Você só pode adicionar um evento") # You can add only one schedule


class ModelPresenca(models.Model):
    DIAS = (
        # The days are in Portuguese
        ('Domingo', 'Domingo'),
        ('Segunda', 'Segunda'),
        ('Terça', 'Terça'),
        ('Quarta', 'Quarta'),
        ('Quinta', 'Quinta'),
        ('Sexta', 'Sexta'),
        ('Sábado', 'Sábado'),
    )
    dia = models.CharField('Dia da Pelada', max_length=10, help_text='Escolha o dia da pelada', choices=DIAS) # day of the event 
    hora_pelada = models.TimeField('Horário da pelada (ex: 19:30)', help_text='Hora em que sua pelada é realizada') # hour of the event 
    dias_antecedencia = models.PositiveIntegerField('Dias antecedência',
                                                    default=1,
                                                    validators=[MinValueValidator(1), MaxValueValidator(6)],
                                                    help_text='Em quantos dias de antecência os peladeiros devem '
                                                              'marcar presença') # numbers of days before event

However, I don't know how to make this event repeat without requiring the user to add the same information every week. I'm thinking of the following algorithm:

def period(request):

    event_data = ModelPresenca.objects.all() # I have always only one object

    hour_timefield = datetime.strptime(h.hora_pelada, '%H:%M') # TimeField to string
    day = event_data.dia # Day of the event 
    b_days = event_data.dias_antecedencia # Number of days before event 

    week_d = week_day(day) # week_day is a function that converts day to int 
    event_d = event_day(week_d, hour_timefield) # event_day is a function that returns the date of full event occur
    conf_d = event_open_date(b_days, event_d) # Is a function that returns date of open to confirm


    n = datetime.now()
    t_str = '{}-{}-{}'.format(n.year, n.month, n.day)
    t_hour = ' {}:{}'.format(n.hour, n.minute)
    today = t_str + t_hour
    today = datetime.strptime(today, '%Y-%m-%d %H:%M')

    if (conf_d <= today) and (today < event_d):
        # Show formulary to confirm presence 
    else:
        # another thing, ie, hidden formulary        


I believe that this last code block have to repeat, but I don't know to do this and I don't know if It's the best way. If anyone can help me, I appreciate.


Solution

  • You can use Django Celery. Celery is an asynchronous task queue/job queue based on distributed message passing. It is focused on real-time operation, but supports scheduling as well.

    Here are first steps for django celery. You could create a post_save method in your model, where you will run a asynchronous task, which will add events as you wish. Additionally there is a Celery beat which enables you creating asynchronous periodic tasks.

    For example:

    @app.task()
    def period():
        # Do your stuff here
    

    and then in your settings file add your celery beat schedule:

    CELERY_BEAT_SCHEDULE = {
     'add-periodic-events': { 
         'task': 'my_app.my_tasks.periodic', # this is a path to your file separated by '.'
         'schedule': crontab(minute=0, hour=0), # Execute daily at midnight.
        },    
    }