【问题标题】:Schema agnostic model design模式不可知模型设计
【发布时间】:2015-05-31 02:15:22
【问题描述】:

是时候提出关于良好设计和性能的问题了。

假设我有三个 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 方法。如果我有一堆模型并且它们通过这些嵌套关系相互关联,那么更改架构意味着搜索所有此类过滤器查询。在我的特殊情况下,我有许多模型存在于不同的应用程序中,并且我的项目变得相当大,所以采用这种方法意味着所有的机会都让我错过了一些东西并创建了一个错误。即使我的测试很好,我也将不得不花费大量时间寻找查询。

一个对我来说似乎更优雅的解决方案是有一个定义 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 导入,使其只发生一次?

提前致谢!

【问题讨论】:

  • 我认为你在正确的轨道上。 Check this post by Tom Christie,他知道一两件事.. ;)
  • 谢谢!我快速浏览了一下,看起来那里有一些可靠的指针。我会详细阅读。

标签: python django orm django-orm


【解决方案1】:

当然,将依赖模式的操作集中在一个地方似乎是个好主意。但是,我认为在 Managers 而不是您建议的 Models 中这样做没有任何优势。

此方法提供了一种将所有依赖于模式的调用集中在一个地方(管理器)的方法

但是管理人员不在一个地方,每个相关模型都会有一个管理人员,而且他们通常放在完全相同的位置 - models.py。在您的示例中,当然没有任何优势,因为在这两种情况下,如果架构发生更改,您都必须更改一种方法。

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

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

循环导入通常也是出现更严重问题的迹象,这可能也是事实。然而,在 Django 中,这种情况并不少见,而且本身并不麻烦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多