Django启动时只执行代码一次?

255 投票
11 回答
144988 浏览
提问于 2025-04-16 22:05

我正在写一个Django的中间件类,希望它在启动时只执行一次,用来初始化一些其他的代码。我参考了sdolan在这里提供的很好的解决方案,但“Hello”这个消息在终端上输出了两次。比如:

from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings

class StartupMiddleware(object):
    def __init__(self):
        print "Hello world"
        raise MiddlewareNotUsed('Startup complete')

在我的Django设置文件中,我已经把这个类加入到MIDDLEWARE_CLASSES列表里。

但是当我使用runserver运行Django并请求一个页面时,终端上却出现了

Django version 1.3, using settings 'config.server'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Hello world
[22/Jul/2011 15:54:36] "GET / HTTP/1.1" 200 698
Hello world
[22/Jul/2011 15:54:36] "GET /static/css/base.css HTTP/1.1" 200 0

有没有人知道为什么“Hello world”会打印两次呢?谢谢。

11 个回答

47

这个问题在博客文章Django项目的入口点钩子中有很好的解答,适用于Django版本1.4及以上。

简单来说,你可以使用<project>/wsgi.py来实现这个功能,这个文件只会在服务器启动时运行一次,而不是在你执行命令或导入某个特定模块时运行。

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")

# Run startup code!
....

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
351

更新:Django 1.7 现在有一个 钩子可以用来处理这个问题

文件:myapp/apps.py

from django.apps import AppConfig
class MyAppConfig(AppConfig):
    name = 'myapp'
    verbose_name = "My Application"
    def ready(self):
        pass # startup code here

文件:myapp/__init__.py

default_app_config = 'myapp.apps.MyAppConfig'

对于 Django 版本小于 1.7

第一种答案似乎不再有效,urls.py 文件在第一次请求时就会被加载。

最近有效的方法是把启动代码放在你任何一个 INSTALLED_APPS 的 init.py 文件里,比如 myapp/__init__.py

def startup():
    pass # load a big thing

startup()

当你使用 ./manage.py runserver 启动时,这段代码会执行两次,但这是因为 runserver 有一些技巧,比如先验证模型等等……正常的部署或者当 runserver 自动重载时,这段代码只会执行一次。

145

来自Pykler的更新:Django 1.7现在有一个钩子可以用来处理这个问题


不要这样做。

你不需要为一次性的启动操作使用“中间件”。

你应该在顶层的urls.py文件中执行代码。这个模块只会被导入和执行一次。

urls.py

from django.confs.urls.defaults import *
from my_app import one_time_startup

urlpatterns = ...

one_time_startup()

撰写回答