Ejecutar código cuando Django se inicia UNA VEZ solamente?

Estoy escribiendo una clase de Django Middleware que quiero ejecutar solo una vez en el inicio, para inicializar otro código arbritario. He seguido la muy buena solución publicada por sdolan aquí , pero el mensaje “Hola” se envía al terminal dos veces . P.ej

from django.core.exceptions import MiddlewareNotUsed from django.conf import settings class StartupMiddleware(object): def __init__(self): print "Hello world" raise MiddlewareNotUsed('Startup complete') 

y en mi archivo de configuración de Django, tengo la clase incluida en la lista MIDDLEWARE_CLASSES .

Pero cuando ejecuto Django usando runserver y solicito una página, me meto en el terminal

 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 

¿Alguna idea de por qué “Hola mundo” se imprime dos veces? Gracias.

Actualización de la respuesta de Pykler a continuación: Django 1.7 ahora tiene un gancho para esto


No lo hagas de esta manera.

No quieres “middleware” para un arranque único.

Desea ejecutar código en el nivel superior urls.py Ese módulo se importa y se ejecuta una vez.

urls.py

 from django.confs.urls.defaults import * from my_app import one_time_startup urlpatterns = ... one_time_startup() 

Actualización: Django 1.7 ahora tiene un gancho para esto

archivo: myapp/apps.py

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

archivo: myapp/__init__.py

 default_app_config = 'myapp.apps.MyAppConfig' 

Para Django <1.7

La respuesta número uno parece no funcionar más, urls.py se carga en la primera solicitud.

Lo que ha funcionado últimamente es colocar el código de inicio en cualquiera de tus INSTALLED_APPS init .py, por ejemplo, myapp/__init__.py

 def startup(): pass # load a big thing startup() 

Cuando se usa ./manage.py runserver … esto se ejecuta dos veces, pero eso se debe a que runserver tiene algunos trucos para validar los modelos primero, etc … implementaciones normales o incluso cuando se recarga automáticamente, esto solo se ejecuta una vez.

Esta pregunta está bien respondida en la entrada del blog Punto de entrada para proyectos Django , que funcionará para Django> = 1.4.

Básicamente, puede usar /wsgi.py para hacerlo, y se ejecutará solo una vez, cuando se inicie el servidor, pero no cuando ejecute comandos o importe un módulo en particular.

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

Si ayuda a alguien, además de la respuesta de pykler, la opción “–noreload” evita que el servidor de ejecución ejecute el comando al inicio dos veces:

 python manage.py runserver --noreload 

Pero ese comando no volverá a cargar el servidor de ejecución después de los cambios de otro código también.

Según lo sugerido por @Pykler, en Django 1.7+ debe usar el enganche explicado en su respuesta, pero si desea que se llame a su función solo cuando se llama al servidor de ejecución (y no al hacer migraciones, se llama migrar, shell, etc.) ), y desea evitar las excepciones de AppRegistryNotReady que debe hacer de la siguiente manera:

archivo: myapp/apps.py

 import sys from django.apps import AppConfig class MyAppConfig(AppConfig): name = 'myapp' verbose_name = 'My Application' 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 

Tenga en cuenta que no puede conectarse a la base de datos o interactuar con modelos dentro de la función AppConfig.ready (consulte la advertencia en la documentación).

Si necesita interactuar con la base de datos en su código de inicio, una posibilidad es usar la señal de connection_created creada para ejecutar el código de inicialización al conectarse a la base de datos.

 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 

Obviamente, esta solución es para ejecutar código una vez por conexión de base de datos, no una vez por inicio de proyecto. Por lo tanto, deseará un valor razonable para la configuración CONN_MAX_AGE para que no vuelva a ejecutar el código de inicialización en cada solicitud. También tenga en cuenta que el servidor de desarrollo ignora CONN_MAX_AGE , por lo que ejecutará el código una vez por solicitud en desarrollo.

El 99% de las veces es una mala idea (el código de inicialización de la base de datos debe ir en las migraciones), pero existen algunos casos de uso en los que no se puede evitar la inicialización tardía y las advertencias anteriores son aceptables.

Si desea imprimir “hola mundo” una vez cuando ejecute el servidor, ponga a print (“hola mundo”) fuera de clase StartupMiddleware

 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"