[python] Django가 ONCE 만 시작할 때 코드를 실행 하시겠습니까?

시작시 한 번만 실행하여 다른 임의의 코드를 초기화하려는 Django Middleware 클래스를 작성 중입니다. 여기 에 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”가 두 번 인쇄되는 이유가 있습니까? 감사.



답변

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()


답변

업데이트 : 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'

장고 <1.7

첫 번째 답변은 더 이상 작동하지 않는 것 같습니다. urls.py는 첫 번째 요청시로드됩니다.

최근에 작동 한 것은 시작 코드를 INSTALLED_APPS init .py 중 하나에 넣는 것입니다.myapp/__init__.py

def startup():
    pass # load a big thing

startup()

./manage.py runserver…를 사용할 때 이것은 두 번 실행되지만 runserver에는 모델을 먼저 검증하는 트릭이 있습니다 … 정상 배포 또는 runserver 자동 다시로드 할 때도 한 번만 실행됩니다.


답변

이 질문은 Django> = 1.4에서 작동하는 Django 프로젝트 의 블로그 게시물 진입 점 후크 에서 잘 대답됩니다 .

기본적으로이를 사용 <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()


답변

pykler의 답변 외에도 “–noreload”옵션을 사용하면 시작시 runserver가 명령을 두 번 실행할 수 없습니다.

python manage.py runserver --noreload

그러나이 명령은 다른 코드 변경 후에도 실행 서버를 다시로드하지 않습니다.


답변

@Pykler가 제안한 것처럼 Django 1.7 이상에서는 그의 답변에 설명 된 후크를 사용해야하지만 실행 서버가 호출 될 때만 (그리고 마이그레이션, 마이그레이션, 셸 등을 호출 할 때가 아닌) 함수가 호출되도록하려면 ), AppRegistryNotReady 예외피하려면 다음과 같이해야합니다.

파일: myapp/apps.py

import sys
from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        if 'runserver' not in sys.argv:
            return True
        # you must import your modules here 
        # to avoid AppRegistryNotReady exception 
        from .models import MyModel
        # startup code here


답변

당신이주의 할 수없는 내부 모델 데이터베이스 또는 상호 작용에 연결 신뢰성 AppConfig.ready기능을합니다 (참조 경고 워드 프로세서를).

시작 코드에서 데이터베이스와 상호 작용해야하는 경우 데이터베이스 connection_created에 연결할 때 신호를 사용하여 초기화 코드를 실행할 수 있습니다.

from django.dispatch import receiver
from django.db.backends.signals import connection_created

@receiver(connection_created)
def my_receiver(connection, **kwargs):
    with connection.cursor() as cursor:
        # do something to the database

분명히이 솔루션은 프로젝트 시작 당 한 번이 아니라 데이터베이스 연결 당 한 번만 코드를 실행하기위한 것입니다. 따라서 CONN_MAX_AGE설정에 적절한 값을 원 하므로 모든 요청에서 초기화 코드를 다시 실행하지 않아도됩니다. 또한 개발 서버는를 무시 CONN_MAX_AGE하므로 개발 요청마다 코드를 한 번씩 실행합니다.

99 %의 시간은 나쁜 생각입니다. 데이터베이스 초기화 코드는 마이그레이션에 들어가야합니다. 그러나 늦은 초기화를 피할 수없고 위의 경고를 수용 할 수있는 사용 사례가 있습니다.


답변

서버를 실행할 때 “hello world”를 한 번 인쇄하려면 StartupMiddleware 클래스에서 print ( “hello world”)를 넣습니다.

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

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

print "Hello world"