J'écris une classe Django Middleware que je souhaite exécuter une seule fois au démarrage, pour initialiser un autre code arbritaire. J'ai suivi la très belle solution postée par sdolan ici , mais le message "Hello" est envoyé deux fois sur le terminal . Par exemple
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
class StartupMiddleware(object):
def __init__(self):
print "Hello world"
raise MiddlewareNotUsed('Startup complete')
et dans mon fichier de paramètres Django, j'ai la classe incluse dans la MIDDLEWARE_CLASSES
liste.
Mais quand je lance Django en utilisant runserver et que je demande une page, j'arrive dans le 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
Des idées pourquoi "Hello world" est imprimé deux fois? Merci.
Réponses:
Mise à jour de la réponse de Pykler ci-dessous: Django 1.7 a maintenant un crochet pour cela
Ne fais pas ça de cette façon.
Vous ne voulez pas de "middleware" pour une chose de démarrage ponctuelle.
Vous souhaitez exécuter du code au niveau supérieur
urls.py
. Ce module est importé et exécuté une fois.urls.py
la source
Mise à jour: Django 1.7 a maintenant un crochet pour cela
fichier:
myapp/apps.py
fichier:
myapp/__init__.py
Pour Django <1.7
La réponse numéro un ne semble plus fonctionner, urls.py est chargé à la première demande.
Ce qui a fonctionné ces derniers temps, c'est de mettre le code de démarrage dans l'un de vos init .py par exemple INSTALLED_APPS
myapp/__init__.py
Lorsque vous utilisez
./manage.py runserver
... cela est exécuté deux fois, mais c'est parce que runserver a quelques astuces pour valider les modèles en premier, etc ... déploiements normaux ou même lorsque runserver se recharge automatiquement, cela n'est exécuté qu'une seule fois.la source
Cette question est bien répondue dans l'article de blog Point d'entrée pour les projets Django , qui fonctionnera pour Django> = 1.4.
Fondamentalement, vous pouvez utiliser
<project>/wsgi.py
pour le faire, et il ne sera exécuté qu'une seule fois, au démarrage du serveur, mais pas lorsque vous exécutez des commandes ou importez un module particulier.la source
Si cela aide quelqu'un, en plus de la réponse de pykler, l'option "--noreload" empêche runserver d'exécuter la commande au démarrage deux fois:
Mais cette commande ne rechargera pas non plus runserver après les modifications d'autres codes.
la source
os.environ.get('RUN_MAIN')
pour n'exécuter votre code qu'une seule fois dans le processus principal (voir stackoverflow.com/a/28504072 )ready(self)
appels multiples tout en ne pouvant les démarrer qu'une seule fois. À votre santé!runserver
démarre par défaut deux processus avec des nombres pid distincts (différents).--noreload
fait démarrer un processus.Comme suggéré par @Pykler, dans Django 1.7+ vous devriez utiliser le hook expliqué dans sa réponse, mais si vous voulez que votre fonction ne soit appelée que lorsque run server est appelé (et non lors de migrations, migrate, shell, etc. sont appelés ), et vous souhaitez éviter les exceptions AppRegistryNotReady vous devez procéder comme suit:
fichier:
myapp/apps.py
la source
Notez que vous ne pouvez pas vous connecter de manière fiable à la base de données ou interagir avec les modèles à l'intérieur de la
AppConfig.ready
fonction (voir l' avertissement dans la documentation).Si vous avez besoin d'interagir avec la base de données dans votre code de démarrage, une possibilité est d'utiliser le
connection_created
signal pour exécuter le code d'initialisation lors de la connexion à la base de données.Évidemment, cette solution consiste à exécuter le code une fois par connexion à la base de données, pas une fois par démarrage de projet. Vous voudrez donc une valeur raisonnable pour le
CONN_MAX_AGE
paramètre afin de ne pas réexécuter le code d'initialisation à chaque demande. Notez également que le serveur de développement ignoreCONN_MAX_AGE
, donc vous exécuterez le code une fois par requête en développement.99% du temps, c'est une mauvaise idée - le code d'initialisation de la base de données devrait aller dans les migrations - mais il existe des cas d'utilisation où vous ne pouvez pas éviter une initialisation tardive et les mises en garde ci-dessus sont acceptables.
la source
my_receiver
fonction elle - même se déconnecter duconnection_created
signal spécifique, ajoutez ce qui suit à lamy_receiver
fonction:connection_created.disconnect(my_receiver)
.si vous voulez imprimer "hello world" une fois lorsque vous exécutez le serveur, mettez print ("hello world") hors de la classe StartupMiddleware
la source