models.py 文件变得庞大,如何拆分比较好?

94 投票
3 回答
19282 浏览
提问于 2025-04-15 13:03

我的上司给出的指示是:“我想避免在 models.py 文件中放任何逻辑。从现在开始,我们只把它当作访问数据库的类,所有的逻辑都放在使用这些模型类的外部类中,或者把它们封装起来。”

我觉得这样做不太对。我认为为了让文件小而把逻辑放在模型之外是个坏主意。如果逻辑最适合放在模型里,那就应该放在那里,不管文件大小如何。

那么,有没有简单的方法可以使用包含功能呢?用PHP的说法,我想向上司提议让 models.py 文件包含其他地方的模型类。从概念上讲,这样可以让模型拥有我们想要的所有逻辑,同时通过增加文件数量来减小单个文件的大小(这可以减少版本控制中出现的冲突等问题)。

所以,有没有简单的方法可以把模型类从 models.py 文件中移除,但仍然让这些模型与所有Django工具正常工作?或者,有没有完全不同但优雅的解决方案来处理“过大”的 models.py 文件问题?任何建议都非常感谢。

3 个回答

6

我不太清楚你可能遇到的具体问题是什么。这里有一些可能的情况和解决办法:

  • 同一个文件里有多个模型

    把它们放到不同的文件里。如果有依赖关系,可以用导入(import)来引入其他模型。

  • models.py里有多余的逻辑或工具函数

    把这些额外的逻辑放到单独的文件里。

  • 用于从数据库中选择某些模型实例的静态方法

    在一个单独的文件中创建一个新的管理器(Manager)

  • 与模型明显相关的方法

    比如save、__unicode__和get_absolute_url就是这样的例子。

117

模型类里面有一些方法来操作模型是很自然的。如果我有一个书籍模型,里面有个方法叫 book.get_noun_count(),那这个方法就应该放在这里——我不想写成 "get_noun_count(book)",除非这个方法确实应该和其他某个包一起使用。(比如,如果我有一个用来访问亚马逊API的包,里面有 "get_amazon_product_id(book)"。)

当Django的文档建议把模型放在一个文件里时,我真的觉得不太舒服,于是我花了几分钟时间从一开始就想办法把它拆分成一个合适的子包。

site/models/__init__.py
site/models/book.py

__init__.py 文件看起来是这样的:

from .book import Book

这样我仍然可以写 "from site.models import Book"。


以下内容仅适用于Django 1.7之前的版本,详情请见 https://code.djangoproject.com/ticket/3591

唯一需要注意的是,由于Django的一个bug,你需要明确设置每个模型的应用名:Django默认认为应用名是模型路径中的倒数第三个部分。"site.models.Book" 结果是 "site",这是对的;但 "site.models.book.Book" 让它认为应用名是 "models"。这真是Django的一个糟糕的设计;它应该去安装的应用列表中查找前缀匹配。

class Book(models.Model):
    class Meta: app_label = "site"

你可能可以用一个基类或者元类来让这个更通用,但我还没去做这件事。

64

Django的设计理念是让你可以构建很多小应用,而不是一个大应用。

在每个大应用里面,其实都有很多小应用在努力挣脱出来。

如果你的 models.py 文件感觉很大,那说明你做得太多了。停下来,放松一下,拆分一下。

找一些更小的、可能可以重复使用的小应用组件或者部分。你不一定要真的去重复使用它们,只要把它们当作可能会重复使用的东西来考虑就行。

想想你未来的升级路径,拆分那些你可能想在某一天替换掉的应用。你不一定要真的去替换它们,但可以把它们看作是将来可能会被更酷的东西替代的独立“模块”。

我们大约有十几个应用,每个 models.py 文件的代码行数都不超过400行。它们都专注于不超过六个不同的类定义。(这不是硬性限制,只是我们代码的观察结果。)

我们经常提前拆分应用。

撰写回答