如何避免在Django中运行两次的AppConfig.ready()方法

Koo*_*oop 34 python django

我想在Django服务器启动时执行一些代码,但我希望它只运行一次.目前,当我启动服务器时,它执行了两次.文档说这可能发生,并且:

您应该在AppConfig类上放置一个标志,以防止重新运行应该执行一次的代码.

知道怎么做到这一点?下面的打印声明仍然执行两次.

from django.apps import AppConfig
import app.mqtt
from apscheduler.schedulers.background import BackgroundScheduler

class MyAppConfig(AppConfig):
    name = 'app'
    verbose_name = "HomeIoT"
    run_already = False

    def ready(self):
        if MyAppConfig.run_already: return
        MyAppConfig.run_already = True
        print("Hello")
Run Code Online (Sandbox Code Playgroud)

Moh*_*dra 23

如果您不想使用,--noreload您可以:

替换应用程序中__init__.py用于指定配置的行:

default_app_config = 'mydjangoapp.apps.MydjangoappConfig'
Run Code Online (Sandbox Code Playgroud)

这样:

import os

if os.environ.get('RUN_MAIN', None) != 'true':
    default_app_config = 'mydjangoapp.apps.MydjangoappConfig'
Run Code Online (Sandbox Code Playgroud)

  • 您也可以在 `ready()` 方法本身中检查 `RUN_MAIN` 环境变量。 (9认同)
  • 在“ready()”中检查“RUN_MAIN”环境变量比处理文件锁或线程锁简单得多。谢谢你! (2认同)
  • 我确实像@alexdlaird 说的那样:在ready 方法中检查RUN_MAIN,它就像一个魅力。我认为这个答案应该是一个很好的答案,因为 --noreload 适用于 runserver,但不适用于例如当您执行 `python manage.pycollectstatic` 时:如果没有 RUN_MAIN 检查防护,您的代码将被执行,而您可能不会不想要。 (2认同)

小智 10

当你使用python manage.py runserver时,Django启动两个进程,一个用于实际的开发服务器,另一个用于在代码更改时重新加载你的应用程序.

您也可以在没有重新加载选项的情况下启动服务器,并且您将看到只运行一个进程只执行一次:

python manage.py runserver --noreload
Run Code Online (Sandbox Code Playgroud)

你可以看到这个链接,它解决了在Django中运行两次的ready()方法


Dan*_* H. 7

我发现这对我有用,无需--noreloadpython manage.py runserver.

检查方法中的环境变量ready()。env 变量在应用程序结束后不会保留,但如果服务器检测到代码更改并且在自动重新加载后,它会保留。

# File located in mysite/apps.py

from django.apps import AppConfig
import os

class CommandLineRunner(AppConfig):
    name = 'mysite'

    def ready(self):
        run_once = os.environ.get('CMDLINERUNNER_RUN_ONCE') 
        if run_once is not None:
            return
        os.environ['CMDLINERUNNER_RUN_ONCE'] = 'True' 

        # The code you want to run ONCE here
  
Run Code Online (Sandbox Code Playgroud)

  • 如果函数从不同的线程调用两次,是否存在竞争条件的风险?是否有可能在环境中定义变量,从而导致代码可能永远不会运行?您可能可以收缩环境来避免这种情况,但我仍然担心竞争条件。 (2认同)

Rob*_*rio 3

您需要实施锁定。这不是一个简单的问题,当您处理进程和线程时,解决方案会感觉不自然。请注意,锁定问题有很多答案,其中有一些更简单的方法:

文件锁:确保 Linux 中应用程序的单个实例(请注意,默认情况下线程共享文件锁,因此需要扩展此答案以考虑线程)。

还有这个答案,它使用一个名为的Python包tendo封装了文件锁实现:/sf/answers/88581181/

Django 本身在django.core.files.locks.