models.py越来越大,最好的分解方法是什么?


91

主管的指示:“我要避免在其中添加任何逻辑models.py。从现在开始,让我们将其用作访问数据库的类,并将所有逻辑保留在使用模型类或包装它们的外部类中。”

我觉得这是错误的方法。我觉得将逻辑保持在模型之外只是为了减小文件大小是一个坏主意。如果模型中的逻辑最好,则无论文件大小如何,逻辑都是真正应该去的地方。

那么,有没有一种简单的方法可以只使用include?用PHP讲,我想向主管建议,我们只是models.py从其他地方获得了include()模型类。从概念上讲,这将使模型具有我们想要的所有逻辑,但可以通过增加文件数量来减小文件大小(从而减少诸如冲突等的版本控制问题)。

因此,有没有一种简单的方法可以从models.py文件中删除模型类,但是仍然可以使模型与所有Django工具一起使用?或者,对于“大” models.py文件的一般问题,是否有完全不同但优雅的解决方案?任何输入将不胜感激。


7
您知道导入语句,对吗?
balpha

7
PS。我不是在冒犯您的意思,我只是想知道您的位置。
balpha

1
是的,但我不知道django的管理工具是否仅使用import语句引入模型即可。我宁愿在这里问,也不愿花费大量时间尝试使用普通的ole导入,只是为了发现django的工具不能很好地与它们配合使用。我承认我是python和django的新手,所以我可能只是对import语句有一个简单的了解……
Eddified

Answers:


64

Django旨在让您构建许多小型应用程序,而不是一个大型应用程序。

在每个大型应用程序内部,都有许多免费的小型应用程序。

如果您models.py觉得自己很大,那您就做得太多了。停止。放松。分解。

查找较小的,可能可重用的小型应用程序组件或组件。您不必实际重用它们。只需将它们视为潜在可重用的对象。

考虑您的升级路径并分解您可能需要替换的应用程序。您不必实际替换它们,但是您可以将它们视为独立的编程“模块”,将来可能会替换为更酷的东西。

我们大约有十二个应用程序,每个应用程序model.py最多不超过400行代码。它们都集中在少于大约六个离散类定义上。(这些不是硬性限制,它们是对我们代码的观察。)

我们经常分解。


1
就点。任何不平凡的Web应用程序都将是几个小型“应用程序”。暗示一下贡献和其他流行的应用程序,用户身份验证是一个应用程序,标记是另一个应用程序,用户配置文件是另一个应用程序,等等
Javier

4
尽管这是“正确”的方式,并且对您有所帮助,但它并不是我一直在寻找的东西。如果无法知道我在寻找哪种答案,我深表歉意。:)
Eddified

@Eddified:如果不这样做,只会变得更糟。立即开始拆分。
S.Lott

有趣的是,此刻,我正在听OSCON的Jacob Kaplan Moss的详尽解释和有充分根据的细节;-)。
Alex Martelli,2009年

13
Glenn Maynard对此的回答要好得多。将复杂的Web应用程序划分为许多应用程序当然是一个好习惯,但是在应用程序内部重构model.py文件也是如此。这两个动作可以是正交的。
Erik

108

模型类很自然地包含对模型进行操作的方法。如果我有一个带有方法的Book模型,book.get_noun_count()那就是它的所属位置-我不想写“ get_noun_count(book)”,除非该方法实际上本质上属于其他软件包。(例如,如果我有一个用于通过“ get_amazon_product_id(book)” 访问Amazon API的程序包,则可能会。)

当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中的一个错误,您需要显式设置每个模型的应用程序:它假定应用程序名称是模型路径中倒数第二个条目。“ site.models.Book”的结果为“ site”,这是正确的;“ site.models.book.Book”使其认为应用程序名称为“ models”。对于Django而言,这是一个非常讨厌的黑客。它可能应该在已安装的应用程序列表中搜索前缀匹配项。

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

您可能可以使用基类或元类对此进行概括,但是我还没有对此感到烦恼。


2
+1我已经成功地使用了它。尽管S. Lott在多个应用程序中都是一个好主意,但这是当前和现在的解决方案。
Alexander Ljungberg,2009年

35
当您的模型紧密相关且本质上相关时,将事物拆分为一堆应用程序不会带来太多好处。
格伦·梅纳德

2
这使我感兴趣。我阅读了发布的django Wiki链接,发现了这一点:“已被验证可以在当前主分支中不使用Meta类app_labels的情况下工作。” 这是否意味着如果您正在使用main分支,我们可以丢弃Meta:app_label的东西吗?令人困惑的是,在针对票证的评论之后,解决了这个问题。
Dan.StackOverflow

2
我刚用trunk(截至今天早些时候,r11286)进行了测试;如果未设置app_name,则该模型根本不会显示在“ sqlall appname”中,并且可能不会由syncdb创建(但我不使用它,因此无法对其进行测试)。这是一个非常令人困惑的错误情况,因为它不会触发任何错误。它只是默默地没有出现。
格伦·梅纳德

2
哇,将近10年了,我仍然喜欢这个解决方案。同意这是比将代码拆分为较小的应用程序更好的方法,我认为这可能导致难以推理的代码库。
Michael Hays '18年

5

我不太了解您可能遇到的许多问题中的哪一个。以下是一些可能的答案:

  • 同一文件中的多个模型

    将它们放入单独的文件中。如果存在依赖关系,请使用import引入其他模型。

  • models.py中的无关逻辑/实用程序功能

    将额外的逻辑放入单独的文件中。

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

    在单独的文件中创建一个新的Manager

  • 与模型明显相关的方法

    保存,例如__unicode__和get_absolute_url。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.