Ich schreibe eine Django Middleware-Klasse, die ich beim Start nur einmal ausführen möchte, um einen anderen britischen Code zu initialisieren. Ich habe die sehr nette Lösung von sdolan hier verfolgt , aber die Nachricht "Hallo" wird zweimal an das Terminal ausgegeben . Z.B
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
class StartupMiddleware(object):
def __init__(self):
print "Hello world"
raise MiddlewareNotUsed('Startup complete')
und in meiner Django-Einstellungsdatei habe ich die Klasse in der MIDDLEWARE_CLASSES
Liste enthalten.
Aber wenn ich Django mit runserver starte und eine Seite anfordere, komme ich ins 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
Irgendwelche Ideen, warum "Hallo Welt" zweimal gedruckt wird? Vielen Dank.
Antworten:
Update von Pyklers Antwort unten: Django 1.7 hat jetzt einen Haken dafür
Mach es nicht so.
Sie möchten keine "Middleware" für eine einmalige Startsache.
Sie möchten Code in der obersten Ebene ausführen
urls.py
. Dieses Modul wird einmal importiert und ausgeführt.urls.py
quelle
Update: Django 1.7 hat jetzt einen Haken dafür
Datei:
myapp/apps.py
Datei:
myapp/__init__.py
Für Django <1,7
Die Antwort Nummer eins scheint nicht mehr zu funktionieren, urls.py wird bei der ersten Anfrage geladen.
Was in letzter Zeit funktioniert hat, ist, den Startcode in eine Ihrer INSTALLED_APPS- Init .py zu setzen, z
myapp/__init__.py
Bei Verwendung von
./manage.py runserver
... wird dies zweimal ausgeführt, aber das liegt daran, dass Runserver einige Tricks hat, um die Modelle zuerst zu validieren usw. ... normale Bereitstellungen oder selbst wenn Runserver automatisch neu geladen wird, wird dies nur einmal ausgeführt.quelle
Diese Frage wird im Blog-Beitrag Entry Point Hook für Django-Projekte , der für Django> = 1.4 funktioniert, gut beantwortet .
Grundsätzlich können Sie dies verwenden
<project>/wsgi.py
, und es wird nur einmal ausgeführt, wenn der Server gestartet wird, nicht jedoch, wenn Sie Befehle ausführen oder ein bestimmtes Modul importieren.quelle
Wenn es jemandem hilft, verhindert die Option "--noreload" zusätzlich zu Pyklers Antwort, dass der Runserver den Befehl beim Start zweimal ausführt:
Dieser Befehl lädt den Runserver jedoch auch nach Änderungen des anderen Codes nicht neu.
quelle
os.environ.get('RUN_MAIN')
, um Ihren Code nur einmal im Hauptprozess auszuführen (siehe stackoverflow.com/a/28504072 )ready(self)
Anrufe verhinderte und sie dennoch nur einmal starten konnte. Prost!runserver
startet standardmäßig zwei Prozesse mit unterschiedlichen (unterschiedlichen) PID-Nummern.--noreload
lässt es einen Prozess starten.Wie von @Pykler vorgeschlagen, sollten Sie in Django 1.7+ den in seiner Antwort erläuterten Hook verwenden. Wenn Sie jedoch möchten, dass Ihre Funktion nur aufgerufen wird, wenn der Ausführungsserver aufgerufen wird (und nicht, wenn Migrationen durchgeführt werden, werden Migration, Shell usw. aufgerufen ), und Sie möchten AppRegistryNotReady-Ausnahmen vermeiden, müssen Sie wie folgt vorgehen :
Datei:
myapp/apps.py
quelle
Beachten Sie, dass Sie keine zuverlässige Verbindung zur Datenbank herstellen oder mit Modellen innerhalb der
AppConfig.ready
Funktion interagieren können (siehe Warnung in den Dokumenten).Wenn Sie in Ihrem Startcode mit der Datenbank interagieren müssen, besteht eine Möglichkeit darin, das
connection_created
Signal zu verwenden, um den Initialisierungscode bei Verbindung mit der Datenbank auszuführen.Offensichtlich dient diese Lösung dazu, Code einmal pro Datenbankverbindung und nicht einmal pro Projektstart auszuführen. Sie möchten also einen sinnvollen Wert für die
CONN_MAX_AGE
Einstellung, damit Sie den Initialisierungscode nicht bei jeder Anforderung erneut ausführen. Beachten Sie auch, dass der Entwicklungsserver dies ignoriertCONN_MAX_AGE
, sodass Sie den Code einmal pro Anforderung in der Entwicklung ausführen.In 99% der Fälle ist dies eine schlechte Idee - Datenbankinitialisierungscode sollte bei Migrationen verwendet werden -, aber es gibt einige Anwendungsfälle, in denen Sie eine späte Initialisierung nicht vermeiden können und die oben genannten Einschränkungen akzeptabel sind.
quelle
my_receiver
Funktion vomconnection_created
Signal zu trennen. Fügen Sie der Funktion insbesondere Folgendes hinzumy_receiver
:connection_created.disconnect(my_receiver)
.Wenn Sie "Hallo Welt" einmal drucken möchten, wenn Sie den Server ausführen, setzen Sie "Drucken" ("Hallo Welt") aus der Klasse StartupMiddleware
quelle