为什么在Django开发服务器中要运行两次run命令?

29

我想在Django开发服务器启动之前做一些事情。为了做到这一点,我创建了一个新的应用程序,将其添加到INSTALLED_APPS的顶部,然后在该应用程序中创建了一个名为management/commands/runserver.py的文件,并添加以下代码:

from django.contrib.staticfiles.management.commands.runserver import Command as RunserverCommand
class Command(RunserverCommand):
    def run(self, *args, **options):
        self.stdout.write('About to start running on ' + self.addr)
        super(Command, self).run(*args, **options)

当然,我实际想做的事情比向stdout写入一行更加复杂,但这是展示问题的最简单的示例。我覆盖run而不是handle或其他某个方法的原因是因为我需要在此代码运行时已经设置self.addr

当我运行./manage.py runserver时,在服务器开始运行之前,“即将在127.0.0.1上开始运行”这行字出现了两次。为什么会发生这种情况,有什么解决办法吗?


你很可能不想编辑运行命令,可以查看此答案中提到的Django启动钩子功能。https://dev59.com/f2w15IYBdhLWcg3wJ4is#16111968Django runserver的自动重新加载功能会使事情运行两次,但这是无害的,只用于开发。在生产环境中,你不应该使用runserver,在生产环境中,启动代码只会运行一次。 - Pykler
这只是为了本地开发而已。 - Taymon
在这种情况下,你不必太担心它运行两次,因为它只是开发环境。你需要以这样的方式编写代码,使其在生产环境中也能正常工作,当你最终在uwsgi或gunicorn下部署时,编辑运行命令是行不通的。 - Pykler
2个回答

40

原来自动重载进程是罪魁祸首。原来自动重载进程获得相同的参数,并且经历与原始进程相同的初始化过程。解决方案是让预服务器代码仅在未在自动重载程序生成的进程中运行时执行,可以通过环境变量检测到。

import os
from django.contrib.staticfiles.management.commands.runserver import Command as RunserverCommand
class Command(RunserverCommand):
    def run(self, *args, **options):
        if os.environ.get('RUN_MAIN') != 'true':
            self.stdout.write('About to start running on ' + self.addr)
        super(Command, self).run(*args, **options)

28
本地开发服务器为自动重新加载器运行单独的进程。您可以通过传递 --noreload 标志来关闭自动重新加载进程。
python manage.py runserver --noreload

这是验证正在发生的事情的完美方式。谢谢! - StephenGodderidge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接