Django的单例体系结构是否使它作为库中的独立ORM变得不可行?

时间:2016-06-20 04:17:45

标签: python django django-models orm django-orm

我喜欢Django ORM。它简单易用,功能强大。

我目前正在为我工​​作的VFX公司开发一些内部网站,我已经使用过Django。与此同时,我们正在开发其他python应用程序和库,以用于生产中的各种上下文。我们的核心库需要与一些数据库进行交互,并且使用像Django这样的ORM会有很多帮助。我知道其他选项,比如SqlAlchemy或PeeWee,但是我想看看Django是否会起作用,因为我在网站上使用它并且我更喜欢它的API。

在库中使用Django作为ORM很棘手(正如我在previous question中探讨的那样),因为Django希望用作带有“apps”的网站。在库中,我可能想要定义任意数量的数据模型,这些模型将存在于库中的适当位置,但不存在于任何Django应用程序中(因为我们没有使用框架的任何其他部分)。到现在为止还挺好。

我可以在库中的任何位置为我的模型创建一个基类,如下所示:

from django.db import models
from django.apps import apps
import django.conf

django.conf_settings.configure(
    DATABASES = ...
)

apps.populate((__name__,))

class LibModel(models.Model):
    class Meta:
        abstract = True
        app_label = __name__

然后在库中的任何地方我都可以用这个基类创建自己的模型。由于我不依赖于数据库名称的“app”,我需要明确说明它们。

class SpecificModel(LibModel):
    # fields go here
    class Meta(LibModel.Meta):
        db_table = "specific_model_table_name"

这让我担心必须模拟“app”的结构。基类中的 name 属性为Django提供了所需的一切,然后Django退出了抱怨没有找到应用程序的问题。其他模型文件可以在任何他们想要的地方生活。

然而,有一个明显的用例,这一切都崩溃了。假设我的Django Web应用程序想要使用公司核心python库中的一些功能,该库现在使用Django ORM进行各种操作。由于我在库中调用了django.conf.settings.configure,因此Django会在尝试运行主应用程序时不止一次地定义设置。

基本上,使用Django ORM的库与Django不兼容。很棒。

这有什么办法吗?我的意思是,它是一个可爱的ORM - 它是否真的不可能以独立的模块化方式使用? Django架构在本质上完全是单身,这使得这不可能吗?

*不重复 我正在尝试使用Django作为ORM的公司python库。一些可能依赖它的东西可能是Django网站本身。我如何绕过Django的单身坚持只设置一次设置配置?或者有可能吗? 这些答案都没有解决这个问题!

2 个答案:

答案 0 :(得分:2)

您可以检查django是否已经配置。

from django.apps import apps
from django.conf import settings

if not apps.ready:
    settings.configure()
    django.setup()

启动Django应用程序时-核心python库可以配置为单独的应用程序,并在启动时加载。

此外,在运行时动态加载应用程序,请检查this answer

答案 1 :(得分:2)

一个简单的答案是如何在独立应用程序中初始化Django,并使其与Django应用程序兼容。

import os
import django

if not 'DJANGO_SETTINGS_MODULE' in os.environ:
    os.environ['DJANGO_SETTINGS_MODULE'] = 'mysettings'

    # # or without DJANGO_SETTINGS_MODULE directly
    # from django.conf import settings
    # settings.configure(DATABASES=... other...)

    django.setup()

# this shouldn't be before DJANGO_SETTINGS_MODULE or settings.configure(...)
from myapp.models import MyModel
# this shouldn't be called before django.setup()
queryset = MyModel.objects.filter(...)

这与Django更加兼容,然后是Oleg Russkin的答案(如果在另一个类似代码或普通Django启动的setup()内部调用代码,则django.setup()可能存在循环依赖的风险项目由manage发起,类似于manage.py,其中django.setup()在内部也由execute_from_command_line(sys.argv)调用。安装程序初始化了与INSTALLED_APPS相关的所有模块,所有url模块,因此初始化了所有视图等。它们很懒,但是仍然很懒。如果setup()调用的任何代码都依赖于此,则条件not apps.ready都无济于事。setup()不可重入,并且启动失败。)


更一般的答案

Django的一个重要概念是支持编写可重用的代码部分(Django术语中的“应用程序”,它们可以独立开发和测试。也可以有依赖关系树,但不受控制)如果可能的话,应避免相互依赖。)期望可重用的应用程序可以更容易地组合到整个项目中(Django术语中的“项目”具有通过Python运行它的所有必要设置。)

Django ORM中唯一不可避免且有用的“单例”是数据库连接 django.db.connectionsdjango.conf.settings,尤其是INSTALLED_APPS。来自同一进程或线程的同一数据库只能使用一个连接。

Django非常容易可配置。一个极端的例子:可以编写一个文件项目,其中所有代码(如设置,模型,URL配置和视图)都定义在一个文件中。这种极端可能仅对某些特殊测试或非常简短的演示或作为练习有用。甚至可以用两个“可重用”应用程序通过一个文件来定义项目:-)

Django还支持“ 旧版数据库”,其中数据库结构与现有的非Django应用程序共享,并且可以通过inspectdb命令创建模型。此类模型中的表名是显式的,不包含应用程序名称。另一方面,应用程序名称前缀对于防止来自独立“应用程序”的相同表名可能发生冲突很有用。一个重要的决定是可以将其用作“旧版”数据库还是普通的Django数据库。

您可以在以下两个解决方案之间进行选择,或将它们组合在一起:

  • 使用例如foo_modelsbar.models并从中导入所有模型,例如到app.models,并将仅将"app"添加到INSTALLED_APPLICATIONS。如果只有一家公司,而没有其他公司,并且可以进行中央名称分配,那么这可能是可行的。 (最简单但天真一点)
  • 对几个应用程序使用命名空间的粗略分隔。您可能应该使用不超过一个带有简单名称且没有应用名称前缀的应用。

请提前考虑migrations **。如果您以后为同一数据库和数据库表的不同子集创建更多项目,而又不将它们分离到更多应用程序且没有应用程序名称空间,它们将可能非常复杂,并且很快将变得不可能。

除了django.db.connections本身以外,Django ORM中确实没有没有“单身人士” 。如果使用更多数据库,则即使使用具有相同表名而没有前缀的两个不同模型,也可以通过DATABASE_ROUTERS将某些表定向到特定数据库。

相关问题