I need help with a custom model method in Django

I'm developing a web app in Django that manages chores on a reoccurring weekly basis. These are the models I've come up with so far. Chores need to be able to be assigned multiple week days and times. So the chore of laundry could be sunday @ 8:00am and wednesday @ 5:30pm. I first want to confirm the models below are the best way to represent this. Secondly, I'm a little confused about model relationships and custom model methods. Since these chores are on a reoccurring basis, I need to be able to check if there has been a CompletedEvent in this week. Since this is row level functionality, that would be a model method correct? Based on the models below, how would I check for this? It has me scratching my head.

models.py:

from django.db import models
from datetime import date

class ChoreManager(models.Manager):
    def by_day(self, day_name):
        return self.filter(scheduledday__day_name = day_name)

    def today(self):
        todays_day_name = date.today().strftime('%A')
        return self.filter(scheduledday__day_name = todays_day_name)

class Chore(models.Model):
    objects = ChoreManager()
    name = models.CharField(max_length=50)
    notes = models.TextField()

    class Meta:
        ordering = ['scheduledday__time']

class ScheduledDay(models.Model):
    day_name = models.CharField(max_length=8)
    time = models.TimeField()
    chore = models.ForeignKey('Chore')

class CompletedEvent(models.Model):
    date_completed = DateTimeField(auto_now_add=True)
    chore = models.ForeignKey('Chore')

然后,你需要做的是:

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)

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))
链接地址: http://www.djcxy.com/p/56532.html

上一篇: Django表单模型的问题

下一篇: 我需要在Django中使用自定义模型方法的帮助