Models.py 变大了,最好的分手方式是什么?

我上司的指示: “我希望避免在 models.py中加入任何逻辑。从现在开始,让我们只使用它作为访问数据库的类,并将所有逻辑保存在使用模型类或包装它们的外部类中。”

我觉得这样不对。我认为,仅仅为了保持文件的小型化而将逻辑排除在模型之外是一个糟糕的主意。如果模型中的逻辑是最好的,那么无论文件大小如何,它都应该放在那里。

那么有没有一种简单的方法来使用 include 呢?在 PHP 语言中,我想建议主管,我们只有 models.py包括()来自其他地方的模型类。从概念上讲,这将允许模型拥有我们想要的所有逻辑,同时通过增加文件数量来降低文件大小(这将导致更少的修订控制问题,如冲突等)。

那么,是否有一种简单的方法可以从 modes.py 文件中删除模型类,但是仍然可以让模型与所有的 Django 工具一起工作呢?或者,是否有一个完全不同但是优雅的解决方案来解决“大型”models.py 文件的一般问题?如有任何意见,我将不胜感激。

18511 次浏览

Django is designed to let you build many small applications instead of one big application.

Inside every large application are many small applications struggling to be free.

If your models.py feels big, you're doing too much. Stop. Relax. Decompose.

Find smaller, potentially reusable small application components, or pieces. You don't have to actually reuse them. Just think about them as potentially reusable.

Consider your upgrade paths and decompose applications that you might want to replace some day. You don't have to actually replace them, but you can consider them as a stand-alone "module" of programming that might get replaced with something cooler in the future.

We have about a dozen applications, each model.py is no more than about 400 lines of code. They're all pretty focused on less than about half-dozen discrete class definitions. (These aren't hard limits, they're observations about our code.)

We decompose early and often.

It's natural for model classes to contain methods to operate on the model. If I have a Book model, with a method book.get_noun_count(), that's where it belongs--I don't want to have to write "get_noun_count(book)", unless the method actually intrinsically belongs with some other package. (It might--for example, if I have a package for accessing Amazon's API with "get_amazon_product_id(book)".)

I cringed when Django's documentation suggested putting models in a single file, and I took a few minutes from the very beginning to figure out how to split it into a proper subpackage.

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

__init__.py looks like:

from .book import Book

so I can still write "from site.models import Book".


The following is only required for versions prior to Django 1.7, see https://code.djangoproject.com/ticket/3591

The only trick is that you need to explicitly set each model's application, due to a bug in Django: it assumes that the application name is the third-to-last entry in the model path. "site.models.Book" results in "site", which is correct; "site.models.book.Book" makes it think the application name is "models". This is a pretty nasty hack on Django's part; it should probably search the list of installed applications for a prefix match.

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

You could probably use a base class or metaclass to generalize this, but I haven't bothered with that yet.

I can't quite get which of many possible problems you might have. Here are some possibilities with answers:

  • multiple models in the same file

    Put them into separate files. If there are dependencies, use import to pull in the additional models.

  • extraneous logic / utility functions in models.py

    Put the extra logic into separate files.

  • static methods for selecting some model instances from database

    Create a new Manager in a separate file.

  • methods obviously related to the model

    save, __unicode__ and get_absolute_url are examples.