Piszę klasę Django Middleware, którą chcę wykonać tylko raz podczas uruchamiania, aby zainicjować inny kod arbritarny. Postępowałem zgodnie z bardzo fajnym rozwiązaniem opublikowanym tutaj przez sdolan , ale wiadomość „Hello” jest wysyłana do terminala dwukrotnie . Na przykład
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
class StartupMiddleware(object):
def __init__(self):
print "Hello world"
raise MiddlewareNotUsed('Startup complete')
aw moim pliku ustawień Django mam klasę uwzględnioną na MIDDLEWARE_CLASSES
liście.
Ale kiedy uruchamiam Django używając runerver i żądam strony, dostaję się do terminala
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
Jakieś pomysły, dlaczego „Hello world” jest drukowane dwukrotnie? Dzięki.
Odpowiedzi:
Aktualizacja odpowiedzi Pyklera poniżej: Django 1.7 ma teraz haczyk do tego
Nie rób tego w ten sposób.
Nie potrzebujesz „oprogramowania pośredniego” do jednorazowego uruchomienia.
Chcesz wykonać kod na najwyższym poziomie
urls.py
. Ten moduł jest importowany i wykonywany raz.urls.py
źródło
Aktualizacja: Django 1.7 ma teraz do tego haczyk
plik:
myapp/apps.py
plik:
myapp/__init__.py
Dla Django <1.7
Wydaje się, że odpowiedź numer jeden już nie działa, adres urls.py jest ładowany przy pierwszym żądaniu.
To, co ostatnio zadziałało, to umieszczenie kodu startowego w dowolnym init .py INSTALLED_APPS, np
myapp/__init__.py
Podczas używania
./manage.py runserver
... to jest wykonywane dwukrotnie, ale to dlatego, że runerver ma kilka sztuczek, aby najpierw sprawdzić poprawność modeli itp ... normalne wdrożenia lub nawet, gdy runerver ładuje się automatycznie, jest to wykonywane tylko raz.źródło
Odpowiedzi na to pytanie można znaleźć w poście na blogu Hak punktu wejścia dla projektów Django , który będzie działał dla Django> = 1.4.
Zasadniczo możesz
<project>/wsgi.py
to zrobić i zostanie uruchomione tylko raz, podczas uruchamiania serwera, ale nie podczas uruchamiania poleceń lub importowania określonego modułu.źródło
Jeśli to pomoże komuś, oprócz pykler za odpowiedź, „--noreload” zapobiega opcja uruchomieniowego z komendy na starcie wykonywania dwukrotnie:
Ale to polecenie nie załaduje ponownie serwera uruchomieniowego po innych zmianach kodu.
źródło
os.environ.get('RUN_MAIN')
aby wykonać kod tylko raz w procesie głównym (patrz stackoverflow.com/a/28504072 )ready(self)
połączeniom, a jednocześnie była w stanie rozpocząć je tylko raz. Twoje zdrowie!runserver
domyślnie uruchamia dwa procesy z różnymi (różnymi) numerami pid.--noreload
sprawia, że rozpoczyna jeden proces.Jak zasugerował @Pykler, w Django 1.7+ powinieneś użyć haka wyjaśnionego w jego odpowiedzi, ale jeśli chcesz, aby twoja funkcja była wywoływana tylko wtedy, gdy wywoływany jest serwer run (a nie podczas wykonywania migracji, wywoływana jest migracja, powłoka itp. ) i chcesz uniknąć wyjątków AppRegistryNotReady , musisz wykonać następujące czynności:
plik:
myapp/apps.py
źródło
Zwróć uwagę, że nie możesz niezawodnie łączyć się z bazą danych ani wchodzić w interakcje z modelami wewnątrz
AppConfig.ready
funkcji (zobacz ostrzeżenie w dokumentacji).Jeśli potrzebujesz wejść w interakcję z bazą danych w swoim kodzie startowym, jedną z możliwości jest użycie
connection_created
sygnału do wykonania kodu inicjalizacyjnego po połączeniu się z bazą danych.Oczywiście to rozwiązanie służy do uruchamiania kodu raz na połączenie z bazą danych, a nie raz na rozpoczęcie projektu. Dlatego będziesz potrzebować rozsądnej wartości
CONN_MAX_AGE
ustawienia, aby nie uruchamiać ponownie kodu inicjalizacji przy każdym żądaniu. Należy również pamiętać, że serwer deweloperski ignorujeCONN_MAX_AGE
, więc kod zostanie uruchomiony raz na żądanie w trakcie tworzenia.W 99% przypadków jest to zły pomysł - kod inicjalizacji bazy danych powinien być przenoszony podczas migracji - ale są pewne przypadki użycia, w których nie można uniknąć późnej inicjalizacji, a powyższe zastrzeżenia są dopuszczalne.
źródło
my_receiver
funkcję odłączyć się odconnection_created
sygnału, w szczególności, należy dodać następujące domy_receiver
funkcji:connection_created.disconnect(my_receiver)
.jeśli chcesz wydrukować "hello world" raz, kiedy uruchomisz serwer, umieść print ("hello world") poza klasą StartupMiddleware
źródło