我正在用Django开发日历应用程序。
相关模型结构如下:
class Lesson(models.Model):
RECURRENCE_CHOICES = (
(0, 'None'),
(1, 'Daily'),
(7, 'Weekly'),
(14, 'Biweekly')
)
frequency = models.IntegerField(choices=RECURRENCE_CHOICES)
lessonTime = models.TimeField('Lesson Time')
startDate = models.DateField('Start Date')
endDate = models.DateField('End Date')
student = models.ForeignKey(Student)
class CancelledLesson(models.Model):
lesson = models.ForeignKey(Lesson)
student = models.ForeignKey(Student)
cancelledLessonDate = models.DateField() # Actual date lesson has been cancelled, this is startDate + Frequency
class PaidLesson(models.Model):
lesson = models.ForeignKey(Lesson)
student = models.ForeignKey(Student)
actualDate = models.DateField() # Actual date lesson took place
paidAmt = models.DecimalField('Amount Paid', max_digits=5, decimal_places=2)
paidDate = models.DateField('date paid')
class CompositeLesson(models.Model):
# only used to aggregate lessons for individual lesson management
lesson = models.ForeignKey(Lesson)
student = models.ForeignKey(Student)
actualDate = models.DateTimeField()
isCancelled = models.BooleanField()
canLesson = models.ForeignKey(CancelledLesson, blank=True, null=True)
payLesson = models.ForeignKey(PaidLesson, blank=True, null=True)
显然,这都在显示属于特定学生的类(class)时引起了问题。我要尝试做的是显示一个表,该表显示学生姓名以及预定类(class)的所有实例。我正在动态计算递归以避免炸毁我的数据库。重复发生的异常(exception)情况(即类(class)取消)存储在其自己的表格中。生成重复时,将根据已取消的类(class)表检查重复情况。
在这里查看我的代码以生成重复发生(以及引起此问题的小目录):Can't get key to display in Django template
我对Python缺乏经验,并且正在使用该项目作为了解许多概念的一种方式,因此,如果我缺少本质上是“Pythonic”的内容,我深表歉意。
最佳答案
问题的关键在于,您使用了少数几个模型来跟踪一个概念,因此引入了很多重复和复杂性。每个其他模型都是Lesson
的“类型”,因此您应该在此处使用继承。此外,大多数其他模型仅跟踪Lesson
的特定特征,因此,实际上不应将其本身作为模型。这就是我要设置的方式:
class Lesson(models.Model):
RECURRENCE_CHOICES = (
(0, 'None'),
(1, 'Daily'),
(7, 'Weekly'),
(14, 'Biweekly')
)
student = models.ForeignKey(Student)
frequency = models.IntegerField(choices=RECURRENCE_CHOICES)
lessonTime = models.TimeField('Lesson Time')
startDate = models.DateField('Start Date')
endDate = models.DateField('End Date')
cancelledDate = models.DateField('Cancelled Date', blank=True, null=True)
paidAmt = models.DecimalField('Amount Paid', max_digits=5, decimal_places=2, blank=True, null=True)
paidDate = models.DateField('Date Paid', blank=True, null=True)
class CancelledLessonManager(models.Manager):
def get_query_set(self):
return self.filter(cancelledDate__isnull=False)
class CancelledLesson(Lesson):
class Meta:
proxy = True
objects = CancelledLessonManager()
class PaidLessonManager(models.Manager):
def get_query_set(self):
return self.filter(paidDate__isnull=False)
class PaidLesson(Lesson):
class Meta:
proxy = True
objects = PaidLessonManager()
您会注意到,我将所有属性移到了
Lesson
上。这是应该的方式。例如,Lesson
具有cancelledDate
字段。如果该字段为NULL,则不会取消它。如果是实际日期,则将其取消。无需其他模型。但是,出于指导目的,我同时保留了
CancelledLesson
和PaidLesson
。这些现在称为Django“代理模型”。他们没有得到自己的数据库表(因此没有讨厌的数据重复)。它们纯粹是为了方便。每个都有一个自定义管理器,以返回适当的匹配Lessons
,因此您可以执行CancelledLesson.objects.all()
并仅获取那些被取消的Lesson
。您还可以使用代理模型在管理员中创建唯一 View 。如果您只想为CancelledLesson
设置一个管理区域,则可以,而所有数据仍进入Lesson
的一个表中。CompositeLesson
不见了,而且很好。这是尝试将其他三个模型组合为一个有凝聚力的东西的产物。这不再是必须的,因此您的查询将大大简化。编辑
我忽略了提及,您可以并且应该将实用程序方法添加到
Lesson
模型中。例如,从数据库的角度来看,虽然通过字段是否为NULL来跟踪已取消/否的跟踪是有意义的,但从编程的角度来看,它并不是那么直观。结果,您可能需要执行以下操作:@property
def is_cancelled(self):
return self.cancelledDate is not None
...
if lesson.is_cancelled:
print 'This lesson is cancelled'
或者:
import datetime
...
def cancel(self, date=None, commit=True):
self.cancelledDate = date or datetime.date.today()
if commit:
self.save()
然后,您可以简单地通过调用
lesson.cancel()
取消类(class),默认情况下,该类(class)将在今天取消。如果您想将来取消它,则可以传递一个日期:lesson.cancel(date=tommorrow)
(其中tomorrow
是datetime
)。如果要在保存之前进行其他处理,请传递commit=False
,它实际上尚未将对象保存到数据库中。然后,在准备就绪时调用lesson.save()
。关于django - 在Django日历应用中处理重复事件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10937660/