2015-11-19 12 views
22

Voglio eseguire qualche codice all'avvio del server Django ma voglio che venga eseguito solo una volta. Attualmente quando avvio il server è eseguito due volte. Documentation dice che questo potrebbe accadere e:Come evitare il metodo AppConfig.ready() in esecuzione due volte in Django

si dovrebbe mettere una bandiera sul vostro classi AppConfig per evitare che il codice ri-esecuzione che dovrebbe essere eseguito esattamente una volta.

Qualche idea su come raggiungere questo obiettivo? L'istruzione di stampa di seguito è ancora eseguita due volte.

from django.apps import AppConfig 
import app.mqtt 
from apscheduler.schedulers.background import BackgroundScheduler 

class MyAppConfig(AppConfig): 
    name = 'app' 
    verbose_name = "HomeIoT" 
    run_already = False 

    def ready(self): 
     if MyAppConfig.run_already: return 
     MyAppConfig.run_already = True 
     print("Hello") 
+0

È che indentazione corretta?'ready' dovrebbe essere all'interno della classe MyAppConfig. –

+1

Hai ragione. Era solo un errore di copia/incolla. L'ho riparato. – Koooop

+2

La doppia stampa si verifica se si esegue '--noreload'? – AKX

risposta

-1

Provare a utilizzare una variabile di istanza, piuttosto che una variabile di classe. Ad esempio:

class MyAppConfig(AppConfig): 
    run_already = False 

    def ready(self): 
     if not self.run_already: 
      print('Hello, world!') 
      self.run_already = True 
+4

Grazie per il consiglio, ma sfortunatamente questo non aiuta. – Koooop

+0

Questo è identico a quello della domanda – user3479125

+0

Strana, ma questa soluzione in base alla documentazione più recente più recente 'In tal caso, scrivere metodi idempotenti o mettere un flag sulle classi AppConfig per impedire il codice di riesecuzione che dovrebbe essere eseguito esattamente una volta. ' – user3479125

2

È necessario implementare il blocco. Non è un problema semplice e la soluzione non risulterà naturale in quanto si tratta di processi e thread. Tieni presente che esistono molte risposte al problema del blocco, alcuni approcci più semplici:

Un blocco file: Ensure a single instance of an application in Linux (nota che i thread condividono il blocco del file per impostazione predefinita, quindi questa risposta deve essere espansa per tenere conto dei thread).

C'è anche questa risposta che utilizza un pacchetto Python chiamato tendo che incapsula l'attuazione di un blocco di file: https://stackoverflow.com/a/1265445/181907

Django si fornisce un file portatile sottratto utilità di bloccaggio in django.core.files.locks.

2

Come detto da Roberto, è necessario implementare il blocco per eseguire questa operazione quando si esegue il server tramite il comando runserver, se si desidera utilizzare la funzionalità auto_reload predefinita.

Django implementa il caricamento automatico tramite threading e quindi importa AppConfig in due thread separati, il thread principale 'command/watch' e il thread 'reload' che esegue il server. Aggiungi una dichiarazione di stampa al modulo e vedrai questo in azione. Il thread 'main' carica i file AppConfig come parte di BaseCommand ed esegue il thread 'reload', quindi li carica di nuovo durante l'avvio del server.

Se si dispone di codice che non può essere eseguito in entrambi questi thread, le opzioni sono alquanto limitate. È possibile implementare un blocco di thread in modo che il thread di "ricarica" ​​non venga eseguito pronto(); è possibile spostarsi in un ambiente di produzione per eseguire il server (ad esempio, Gunicorn è molto veloce da configurare, anche per i test); oppure puoi chiamare il tuo metodo in un altro modo piuttosto che usare ready().

Si consiglia di passare a un ambiente corretto, ma l'opzione migliore dipende in realtà da cosa si deve fare esattamente il metodo che si sta chiamando.

2

Quando si utilizza python manage.py runserver Django avvia due processi, uno per il server di sviluppo effettivo e altro per ricaricare l'applicazione quando il codice cambia.

È anche possibile avviare il server senza l'opzione di ricarica, e vedrete solo un processo in esecuzione verrà eseguito solo una volta:

python manage.py runserver --noreload 

You can see this links,it resolve that ready() method running twice in Django

Problemi correlati