Mat*_*esi 5 django django-models
我正在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)
Run Code Online (Sandbox Code Playgroud)
显然,这都会导致显示属于特定学生的课程的问题.我试图做的是显示一个表格,显示学生姓名加上所有预定课程的实例.我正在动态计算重复,以避免炸毁我的数据库.重复的例外(即课程取消)存储在他们自己的表中.生成重复时,将根据取消的课程表检查重复.
请参阅我的代码以生成重复(以及此问题导致的小目录):无法获取在Django模板中显示的键
我对Python相对缺乏经验,而且我正在使用这个项目来了解很多概念,所以如果我错过了本质上是"Pythonic"的东西,我道歉.
问题的关键部分在于您使用少数模型来跟踪一个概念,因此您会引入大量重复和复杂性.每个附加模型都是"类型" Lesson,所以你应该在这里使用继承.另外,大多数附加模型仅仅跟踪a的特定特征,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()
Run Code Online (Sandbox Code Playgroud)
你会注意到我将所有属性都移到了Lesson.这是应该的方式.例如,Lesson有一个cancelledDate字段.如果该字段为NULL,则不会取消.如果是实际日期,则取消.不需要另一种模型.
但是,我已将两者都留下CancelledLesson并PaidLesson用于指导目的.这些现在是Django所谓的"代理模型".他们没有自己的数据库表(所以没有讨厌的数据重复).它们纯粹是为了方便.例如,每个都有一个自定义管理器来返回相应的匹配Lessons,因此您可以执行CancelledLesson.objects.all()并仅获取Lesson被取消的那些.您还可以使用代理模型在管理员中创建唯一视图.如果你想只为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'
Run Code Online (Sandbox Code Playgroud)
要么:
import datetime
...
def cancel(self, date=None, commit=True):
self.cancelledDate = date or datetime.date.today()
if commit:
self.save()
Run Code Online (Sandbox Code Playgroud)
然后,您只需通过呼叫取消课程lesson.cancel(),它将默认取消它今天.如果您希望将来取消它,您可以传递日期:( lesson.cancel(date=tommorrow)其中tomorrow是a datetime).如果要在保存,传递之前进行其他处理commit=False,它实际上不会将对象保存到数据库中.然后,lesson.save()当你准备好时打电话.