[Django]-Custom model method in Django

3👍

Then all you need to do is:

monday_of_week = some_date - datetime.timedetla(days=some_date.weekday())
end_of_week = date + datetime.timedelta(days=7)
chore = Chore.objects.get(name='The chore your looking for')

ScheduledDay.objects.filter(completed_date__gte=monday_of_week,
                            completed_date__lt=end_of_week,
                            chore=chore)

2👍

A neater (and faster) option is to use Bitmasks!

Think of the days of the week you want a chore to be repeated on as a binary number—a bit for each day. For example, if you wanted a chore repeated every Tuesday, Friday and Sunday then you would get the binary number 1010010 (or 82 in decimal):

S S F T W T M
1 0 1 0 0 1 0 = 1010010

Days are reversed for sake of illustration

And to check if a chore should be done today, simply get the number of that day and do an &:

from datetime import datetime as dt

if dt.today().weekday() & 0b1010100:
    print("Do chores!")

Models

Your models.py would look a bit like this:

from django.contrib.auth.models import User
from django.db import models
from django.utils.functional import cached_property


class Chore(models.Model):
    name = models.CharField(max_length=128)
    notes = models.TextField()


class ChoreUser(models.Model):
    chore_detail = models.ForeignKey('ChoreDetail')
    user = models.ForeignKey('ChoreDetail') 

    completed_time = models.DateTimeField(null=True, blank=True)


class ChoreDetail(models.Model):
    chore = models.ForeignKey('Chore')
    chore_users = models.ManyToManyField('User', through=ChoreUser)

    time = models.DateTimeField()
    date_begin = models.DateField()
    date_end = models.DateField()
    schedule = models.IntegerField(help_text="Bitmask of Weekdays")

    @cached_property
    def happens_today(self):
        return bool(dt.today().weekday() & self.weekly_schedule)

This schema has a M2M relationship between a User and a Chore’s Schedule. So you can extend your idea, like record the duration of the chore (if you want to), or even have many users participating in the same chore.

And to answer your question, if you’d like to get the list of completed events this week, you could could put this in a Model Manager for ChoreUser:

from datetime import datetime as dt, timedelta


week_start = dt.today() - timedelta(days=dt.weekday())
week_end = week_start + timedelta(days=6)

chore_users = ChoreUser.objects.filter(completed_time__range=(week_start, week_end))

Now you have all the information you need in a single DB call:

user = chore_users[0].user
time = chore_users[0].chore_detail.time
name = chore_users[0].chore_detail.chore.name
happens_today = chore_users[0].chore_detail.happens_today

You could also get all the completed chores for a user easily:

some_user.choreuser_set.filter(completed_time__range=(week_start, week_end))

Leave a comment