Exclude objects with a related date range

Using these (simplified of course) models:

class Person(models.Model):
    name = models.CharField()

class InactivePeriod(models.Model)
    person = models.ForeignKeyField(Person)
    start_date = models.DateField()
    end_date = models.DateField()

class Template(models.Model):
    day = models.CharField() #choices = monday, tuesday, etc...
    person = models.ForeignKeyField(Person)

class TheList(models.Model):
    person = models.ForeignKeyField(Person)
    date = models.DateField(default=datetime.today)
    attended = models.BooleanField(default=False)

I have a workflow where people call in to sign up for a daily event (there will be no online registration). Originally my users were going to enter each attendee manually each day as they call by creating a TheList record, and then check off if they attended. However, as each event has regulars that typically come on the same days. It was decided that I would provide a Template table, where the user could designate that 'Mike' is a regular on 'Monday' and then I would use a cronjob to automatically populate the TheList table with records for people who were regulars for that day. Then, my user interface is going to automatically filter the TheList list view down to the current day's attendees, and then my users can make any changes as necessary. It just reduces the amount of input they need to do.

The wrinkle is that my users requested that they be able to designate someone as inactive for a period of time. If a Person has a related InactivePeriod record where 'today' falls between that record's start_date and end_date, my cronjob will omit that Person. I decided against a simple 'active' BooleanField as I think it will be easier for them to not have to remember if someone is inactive or not, and to not have to worry about communicating that they marked someone inactive to another user.

My script is essentially:

def handle(self, *args, **options):
    today = datetime.today()
    day = str(today.weekday()) #we store this as a string as it is a charfield

    is_inactive_today = (Q(person__inactiveperiod__start_date__lte=today) & \ 
                         Q(person__inactiveperiod__end_date__gte=today))

    attendance_list = []
    for t in models.Template.objects.filter(day=day).exclude(is_inactive_today):
        attendance_list.append(models.TheList(person=t.person, date=today))
    models.TheList.objects.bulk_create(attendance_list)

assuming 'today' is 10/11/2024 (october 11 2024), if I add two InactivePeriod's for a Person where the date ranges are (10/9/2024, 10/10/2024) and (10/12/2024, 10/13/2024), the query incorrectly does not return that Person's related Template record despite the fact that both of their InactivePeriod's do not include today, and as such I cannot create an appropriate TheList record. If I remove either of the records, leaving just one InactivePeriod record, the query does return the related Template record successfully.

Is this possible to do using the ORM or do I have write some logic into my for loop?

Django DB stores datetime including timezone information.

Problems resulting from this are expected. Instead of datetime, try using Django's built-in timezone.

It looks like your model and view need to be modified.

from django.utils import timezone

now = timzone.now()
Вернуться на верх