如何在console_script中调用django.setup()?

时间:2016-09-26 13:32:10

标签: python django python-import hang

目前的django文档告诉我:

  

django.setup()只能调用一次。

     

因此,请避免将可重用的应用程序逻辑放在独立脚本中,以便您必须从应用程序中的其他位置导入脚本。如果你无法避免,请将调用django.setup()放在if块中:

if __name__ == '__main__':
    import django
    django.setup()

来源:Calling django.setup() is required for “standalone” Django usage

我在setup.py中使用入口点。这样我就没有__name__ == '__main__'

问题

如果使用console_scripts,如何确保只调用一次django.setup()?

我应该在哪里放置django.setup()

背景

我遇到的实际错误:Django挂起。原因如下:https://code.djangoproject.com/ticket/27176

我想将我的应用程序移植到当前的django版本。更改为管理命令不是一种选择,因为其他(第三方应用程序)依赖于我的控制台脚本的存在。

5 个答案:

答案 0 :(得分:8)

有同样的问题(或类似的东西)。我解决了这个问题:

[警告:肮脏的解决方案]

if not hasattr(django, 'apps'):
    django.setup()

这样,即使多次导入它也只会被调用一次

答案 1 :(得分:3)

https://docs.djangoproject.com/en/1.10/_modules/django/#setup我们可以看到django.setup实际上做了什么。

  

配置设置(这是访问的一个副作用   第一个设置),配置日志记录并填充应用程序注册表。   如果set_prefix为True,则设置thread-local urlresolvers脚本前缀。

因此,基本上为了确保设置已经完成,我们可以检查应用程序是否已准备好并且设置已配置

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

if not apps.ready and not settings.configured:
    django.setup()

答案 2 :(得分:2)

我在两个生产CLI python包中工作,在django.setup()中显式调用console_scripts

您应该注意的最重要的事情是DJANGO_SETTINGS_MODULE路径中的env

您可以在shell脚本中设置此值,甚至可以在python脚本中加载默认设置。

以下是示例:

# setup.py
entry_points={
    'my-cli = mypackage.cli:main'
}

# cli.py
import logging
from os import environ as env


if not 'DJANGO_SETTINGS_MODULE' in env:
    from mypackage import settings
    env.setdefault('DJANGO_SETTINGS_MODULE', settings.__name__)


import django
django.setup()

# this line must be after django.setup() for logging configure
logger = logging.getLogger('mypackage')

def main():
    # to get configured settings
    from django.conf import settings

    # do stuffs


if __name__ == '__main__':
    main()

答案 3 :(得分:1)

由于我喜欢无条件代码,因此我使用此解决方案。它与django文档中的相似,但是可以避免使用ul if __name__ == '__pain__'

带代码的文件:

# utils/do_good_stuff.py
# This file contains the code
# No `django.setup()` needed
# This code can be used by web apps and console scripts.

from otherlib import othermethod

def say_thank_you():
    ...

主要文件:

# do_good_stuff_main.py
import django
django.setup()

def say_thank_you_main():
    from myapp import do_good_stuff
    return do_good_stuff()

setup.py:

    'console_scripts': [
        'say_thank_you=myapp.do_good_stuff_main:say_thank_you_main',
    ...

这是我目前的解决方案。 Ffeeback欢迎。有什么需要改进吗?

答案 4 :(得分:0)

(至少在Django 2.2.5中),设置是在导入时配置的。 django.setup()对其进行配置,因为它会导入它们。两次调用django.setup()的问题在于,您将两次填充settings.INSTALLED_APPS中指定的应用程序,这可能会导致各种问题。

if not apps.ready:检查就是您应该使用的所有方法:

import django

if not apps.ready:
    django.setup()

使用if not (apps.ready or settings.configured):-是错误的,因为设置可能已在其他位置配置了import语句,并且可能仍未填充应用程序,因此在需要时无法调用django.setup()

也就是说,如果您知道独立的入口点(例如main.py),则可以在没有条件的情况下在此处调用它。仅当存在实际运行脚本两次的风险时才需要此条件,也许是通过将独立模块导入另一个独立模块,以便它们都调用django.setup。多次导入一个模块只会运行一次。