架构不可知模型设计

时间:2015-05-31 02:15:23

标签: python django orm django-orm

现在是关于良好设计和表现的问题的时候了。

说我有三个django型号:

class Student(Model):
  classroom = ForeignKey('Classroom')
  # student info

class Classroom(Model):
  teacher = ForeignKey('Teacher')
  # classroom info

class Teacher(Model):
  # teacher info

我想确保一个视图有一个很好的方式来访问教师拥有的所有学生。要做到这一点,在教师模型

上定义一个方法可能是有意义的
def get_students(self): 
  # code

现在,有几种方法可以做到这一点。我的优先事项之一是使每个模型与整个数据库模式保持相对不可知。因此,我不太喜欢以下解决方案:

def get_students(self):
  return Student.objects.filter(classroom__teacher=self)

该解决方案依赖于学生通过课堂与教师联系;如果我改变这种结构(也许学生需要直接与教师联系,而不是通过教室),我现在必须改变get_students方法。如果我有一堆模型,并且它们通过这些嵌套关系彼此相关,那么更改模式意味着搜索所有这些过滤查询。在我的特定情况下,我有许多模型存在于不同的应用程序中,我的项目变得非常大,所以采用这种方法意味着所有邀请各种机会让我错过一些东西并创建一个bug。即使我的测试很好,我也要花很多时间寻找查询。

对我来说似乎更优雅的解决方案是让学生经理定义for_teacher方法:

class StudentManager(Manager):
  def for_teacher(self, teacher):
    return self.filter(classroom__teacher=teacher)

现在,我的get_students方法看起来像这样:

def get_students(self):
  return Students.objects.for_teacher(self)

通过这种方法,我抽象了一些东西,以便教师不知道它与学生的关系(即通过课堂)。它所知道的是它与学生有某种关系。当然,如果我更改架构,我将不得不更改StudentManager。但是,如果我再次想象一个项目中有许多模型通过不同的模型与其他模型相关,那么这种方法提供了一种方法,可以将所有与模式相关的调用集中在一个地方(管理者)。这使我不必在各种模型中查询查询(也许还有视图)。

问题是,这是一种理智的方法吗?如果没有,处理这个问题的首选方法是什么?

一个必然结果:

如上所述,我的项目在一堆应用程序中有很多模型,他们需要以某种方式了解彼此。所以现在我们有一个额外的问题:如果Teacher包含get_students方法而Student有get_teacher方法,我现在遇到循环模块依赖项。这个新问题的潜在解决方案是这个版本的get_students(get_teacher):

def get_students(self):
  from student.models import Student
  return Student.objects.for_teacher(self)

我来自一个将进口放在程序顶端的世界,所以这对我来说似乎有点奇怪。这是一种合理的方法吗?在进行这样的动态导入时是否有性能方面的考虑? Python会在get_students方法中缓存Student导入,所以只发生一次吗?

提前致谢!

1 个答案:

答案 0 :(得分:0)

当然,将您的架构相关操作集中在一个地方似乎是一个好主意。但是,我建议Managers代替Models,而不是models.py这样做有什么好处。

此方法提供了一种方法,可以将所有与架构相关的调用集中在一个地方(管理员)

但是管理者并不在一个地方,每个相关模型都会有一个,而且它们通常放在完全相同的位置 - Managers。在您的示例中,肯定没有优势,因为在这两种情况下,如果架构发生更改,您将不得不更改一个方法。

不要误解我,StudentManager.for_teacher()很棒,Teacher.get_students()根据您的需求和访问模式可能比{{1}}更有意义。但是从封装的角度来看,我没有看到优势。

对于导入,如果有必要避免循环导入,那么在函数中导入模块是常见的并且被接受,即使它不像Pythonic。 PEP 8 advises against it,但没有说明原因。最经常被引用的原因(根据我的经验)是,当导入遍布文件时,跟踪模块的依赖性变得更加困难。性能不是一个重要的考虑因素,因为Python确实cache the imported module

通常情况下,循环进口通常表明出现更严重的问题。然而,在Django中,它本身并不罕见,并且本身并不麻烦。