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()