我正在用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,则不会取消它。如果是实际日期,则将其取消。无需其他模型。

但是,出于指导目的,我同时保留了CancelledLessonPaidLesson。这些现在称为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)(其中tomorrowdatetime)。如果要在保存之前进行其他处理,请传递commit=False,它实际上尚未将对象保存到数据库中。然后,在准备就绪时调用lesson.save()

关于django - 在Django日历应用中处理重复事件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10937660/

10-15 23:27