Heim >Backend-Entwicklung >Python-Tutorial >Wie wird Autoreload im Django-Entwicklermodus implementiert?
Bei der Entwicklung von Django-Anwendungen ist es besonders praktisch, den Entwicklermodus zum Starten des Dienstes zu verwenden. Zum Ausführen des Dienstes benötigen Sie nur den Python-Manage.py-Runserver, der einen sehr benutzerfreundlichen automatischen Lademechanismus bietet Sie müssen das Programm manuell neu starten, um den Code zu ändern und Feedback zu sehen. Als ich zum ersten Mal damit in Kontakt kam, fand ich diese Funktion benutzerfreundlicher und hielt es nicht für eine besonders fortschrittliche Technologie. Später, als ich Zeit hatte, dachte ich darüber nach, was ich tun würde, wenn ich dieses automatische Nachladen implementieren würde, aber es gab immer einige Dinge, die ich nicht herausfinden konnte. Meine erste Reaktion schien zu sein, dass ich zu viel Ehrgeiz und zu wenig Geschick hatte. Also habe ich einige Zeit damit verbracht, zu studieren, wie Django das automatische Laden implementiert. Ich habe mir den Quellcode für jeden Schritt angesehen und nicht zugelassen, dass irgendetwas als selbstverständlich angesehen wird:
1. Bevor wir auf das Thema eingehen, gibt es tatsächlich einen langen Absatz mit Unsinn darüber, wie der Befehl runserver ausgeführt wird. Er hat wenig mit dem Thema zu tun, daher werde ich ihn kurz erwähnen:
Nach der Eingabe von python manage.py runserver In der Befehlszeile sucht Django nach dem Befehl runserver. Das Ausführungsmodul befindet sich schließlich im Modul
djangocontribstaticfilesmanagementcommandsrunserver.py:
#django\contrib\staticfiles\management\commands\runserver.pyfrom django.core.management.commands.runserver import \ Command as RunserverCommandclass Command(RunserverCommand): help = "Starts a lightweight Web server for development and also serves static files."
Die Ausführungsfunktion dieses Befehls ist hier:
#django\core\management\commands\runserver.pyclass Command(BaseCommand): def run(self, **options): """ Runs the server, using the autoreloader if needed """ use_reloader = options['use_reloader'] if use_reloader: autoreload.main(self.inner_run, None, options) else: self.inner_run(None, **options)
Hier sind die Urteile über use_reloader. Wenn wir im Startbefehl nicht --noreload hinzufügen, wechselt das Programm zur Funktion autoreload.main. Wenn wir es hinzufügen, wechselt es zu self.inner_run und startet die Anwendung direkt.
Tatsächlich ist aus den Parametern von autoreload.main ersichtlich, dass es eine gewisse Kapselung von self.inner_run geben sollte. Der Mechanismus von autoreload liegt in diesen Kapselungen.
PS: Als ich mir den Quellcode angesehen habe, habe ich festgestellt, dass der Befehlsmodus von Django wunderbar implementiert ist und es sich lohnt, ihn zu erlernen.
2. Autoreload-Modul. Schauen Sie sich autoreload.main() an:
#django\utils\autoreload.py:def main(main_func, args=None, kwargs=None): if args is None: args = () if kwargs is None: kwargs = {} if sys.platform.startswith('java'): reloader = jython_reloader else: reloader = python_reloader wrapped_main_func = check_errors(main_func) reloader(wrapped_main_func, args, kwargs)
Hier unterscheiden wir zwischen Jpython und anderen Pythons. Ignorieren Sie Jpython zuerst. check_errors Ignorieren Sie einfach die Fehlerbehandlung von main_func. Schauen Sie sich python_reloader an:
#django\utils\autoreload.py:def python_reloader(main_func, args, kwargs): if os.environ.get("RUN_MAIN") == "true": thread.start_new_thread(main_func, args, kwargs) try: reloader_thread() except KeyboardInterrupt: pass else: try: exit_code = restart_with_reloader() if exit_code < 0: os.kill(os.getpid(), -exit_code) else: sys.exit(exit_code) except KeyboardInterrupt: pass
Als ich zum ersten Mal hierher kam, war die Variable RUN_MAIN in der Umgebungsvariablen nicht „wahr“. oder sogar Nein, also gehen Sie anderswo hin und schauen Sie sich restart_with_reloader an:
#django\utils\autoreload.py:def restart_with_reloader(): while True: args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions] + sys.argv if sys.platform == "win32": args = ['"%s"' % arg for arg in args] new_environ = os.environ.copy() new_environ["RUN_MAIN"] = 'true' exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ) if exit_code != 3: return exit_code
Hier starten wir zunächst eine While-Schleife und ändern uns intern RUN_MAIN auf „true“ setzen und dann mit der os.spawnve-Methode einen Unterprozess (Unterprozess) öffnen. Schauen Sie sich die Anweisungen von os.spawnve an:
_spawnvef(mode, file, args, env, execve)
Tatsächlich habe ich gerade die Befehlszeile noch einmal angepasst und python manage.py runserver erneut ausgeführt.
Schauen Sie sich als Nächstes die while-Schleife in restart_with_reloader an. Beachten Sie, dass die einzige Bedingung für das Beenden der while-Schleife exit_code!=3 ist. Wenn der untergeordnete Prozess nicht beendet wird, stoppt er beim Schritt os.spawnve. Wenn der untergeordnete Prozess beendet wird und der Exit-Code nicht 3 ist, wird die Schleife beendet, wenn er 3 ist neu erstellt. Aus dieser Logik können wir den Mechanismus des automatischen Neuladens erraten: Der aktuelle Prozess (Hauptprozess) führt tatsächlich nichts aus, sondern überwacht den laufenden Status des untergeordneten Prozesses. Der untergeordnete Prozess ist der echte, wenn der untergeordnete Prozess mit „exit_code=3“ beendet wird (Es sollte an der Erkennung liegen Wenn die Datei geändert wird), starten Sie den Unterprozess erneut, und der neue Code wird natürlich wirksam, wenn der Unterprozess mit „exit_code! = 3“ beendet wird, wird auch der Hauptprozess beendet Das gesamte Django-Programm wird ausfallen. Dies ist nur eine Vermutung und wird im Folgenden überprüft.
3. Untergeordneter Prozess. Oben gibt es tatsächlich eine Frage: Warum generiert der untergeordnete Prozess keinen untergeordneten Prozess? Der Grund dafür ist, dass die Umgebungsvariable RUN_MAIN im Hauptprozess auf true geändert wird, wenn der untergeordnete Prozess zur Funktion python_reloader wechselt:
#django\utils\autoreload.py:def python_reloader(main_func, args, kwargs): if os.environ.get("RUN_MAIN") == "true": thread.start_new_thread(main_func, args, kwargs) try: reloader_thread() except KeyboardInterrupt: pass else: try: exit_code = restart_with_reloader() if exit_code < 0: os.kill(os.getpid(), -exit_code) else: sys.exit(exit_code) except KeyboardInterrupt: pass
Wenn die Bedingung erfüllt ist, erfolgt eine andere logische Verzweigung als der Hauptprozess. Öffnen Sie hier zunächst einen Thread und führen Sie main_func aus, das oben Command.inner_run ist. Das Thread-Modul hier wird wie folgt importiert:
#django\utils\autoreload.py:from django.utils.six.moves import _thread as thread
Die Rolle der sechs Module besteht hier darin, mit verschiedenen Pythons kompatibel zu sein Versionen:
[codeblock six]#django\utils\six.pyclass _SixMetaPathImporter(object):"""A meta path importer to import six.moves and its submodules. This class implements a PEP302 finder and loader. It should be compatible with Python 2.5 and all existing versions of Python3"""官网说明:# https://pythonhosted.org/six/Six: Python 2 and 3 Compatibility Library Six provides simple utilities for wrapping over differences between Python 2 and Python 3. It is intended to support codebases that work on both Python 2 and 3 without modification. six consists of only one Python file, so it is painless to copy into a project.
Wenn das Programm also sowohl auf Python2 als auch auf Python3 und Lupin laufen möchte, ist sechs ein wichtiges Werkzeug. Dann nehmen Sie sich etwas Zeit, schauen Sie sich sechs an und markieren Sie sie.
Dann öffne einen reloader_thread:
=== change ==3) change ==1)
ensure_echo_on() Eigentlich habe ich es noch nicht verstanden, Es scheint, als ob Sie es für die Unix-ähnliche Systemdateiverarbeitung zuerst überspringen sollten.
USE_INOTIFY ist auch eine Variable, die sich auf Systemdateioperationen bezieht. Wählen Sie die Methode zum Erkennen von Dateiänderungen basierend darauf, ob inotify verfügbar ist.
While-Schleife: Überprüfen Sie alle 1 Sekunde den Dateistatus. Wenn sich die normale Datei ändert, wird der Prozess mit dem Exit-Code 3 beendet. Wenn der Hauptprozess erkennt, dass der Exit-Code 3 ist, wird er neu gestartet der untergeordnete Prozess. . . . Dies hängt mit dem oben Gesagten zusammen; wenn es sich nicht um eine gewöhnliche Dateiänderung handelt, sondern um I18N_MODIFIED (Dateiänderung mit dem Suffix .mo, binäre Bibliotheksdatei usw.), dann bedeutet dies, dass beim nächsten Mal der geladene Bibliothekscache geleert werden muss .
Das Obige ist der Prozess des automatischen Neulademechanismus. Es gibt noch einige Details, die nicht besonders klar sind, wie zum Beispiel die Erkennung von Dateiänderungen in verschiedenen Betriebssystemen, aber das sind sehr detaillierte Dinge und betreffen nicht den Hauptprozess. Nachdem ich dies gelesen hatte, fragte ich mich erneut, was ich tun würde, wenn ich gebeten würde, den Mechanismus zum automatischen Nachladen zu entwerfen. Jetzt lautet meine Antwort: Verwenden Sie direkt die Datei djangoutilsautoreload.py. Tatsächlich ist dies ein sehr unabhängiges Modul und es kann als universelle Autoreload-Lösung verwendet werden. Ich habe es sogar selbst geschrieben.
Das obige ist der detaillierte Inhalt vonWie wird Autoreload im Django-Entwicklermodus implementiert?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!