.. _migrations: .. index:: single: Migrationen single: Datenbank-Tabellen single: Datenbank single: SQL single: Migrationsdatei single: Versionierung single: git single: makemigrations single: migrate single: sqlmigrate Migrationen ************************** Um die Daten, die den Models zugewiesen werden, später auch persistent speichern zu können, müssen wir die entsprechenden **Datenbank-Tabellen** anlegen. Dies geschieht aber nicht manuell, sondern wird über sogenannte ``Migrationen`` gelöst. Ein Wort vorweg ============================= Django erstellt also nur auf Grundlage unserer Models entsprechende Datenbank-Tabellen. Das ist in vielen Web-Frameworks übliches Vorgehen, da ein Projekt meist von mehreren Entwicklern und Designern erstellt wird. Um dem gesamten Team die selbe Datenbankstruktur zu garantieren, sind Migrationsdateien ein vorteilhafter Weg, dies zu erreichen. Immer, wenn wir nun ein Model verändern, müssen wir folglich auch eine neue Migrations-Datei erstellen, die als Grundlage für die eigentliche Migration dient. .. warning:: **Löschen von Migrationsdateien** Von Django erstellte Migrationsdateien sollten nur in den seltensten Fällen gelöscht oder manuell bearbeitet werden. Gerade am Anfang eines Projekts passiert es aber oft, dass man ab und an ``reinen Tisch`` machen und alle Migrationsdateien löschen möchte. Unter Linux/Unix-Systemen bieten sich folgende Kommandos an, um die Dateien zu löschen: .. code-block:: shell find . -path "*/migrations/*.py" -not -name "__init__.py" -delete find . -path "*/migrations/*.pyc" -delete Die ``__init__.py`` Dateien werden nicht aus den Migrations-Verzeichnissen gelöscht, da es sich bei diesen um Python-Packages handeln muss. Zusätzlich werden die kompilierten ``pyc`` Dateien entfernt. .. admonition:: Best Practice: Versionieren von Migrations-Dateien Erstellte Migrationsdateien müssen auf jeden Fall ins ``git`` - Repository übernommen und versioniert werden. Wird dies nicht gemacht, haben später womöglich nicht alle Team-Member die selbe Datenbankstruktur. Das führt unweigerlich ins Chaos. .. admonition:: Best Practice: Arbeiten im Team Das Ändern eines Models und das sich daraus ergebende Ändern der Persistenz-Ebene eines Softwareprojekts ist eine Aktion, die gut überlegt und geplant werden muss, vor allem, wenn im Team gearbeitet wird. Als ``best practice`` gilt, dass Änderungen am Model im Team abgesprochen werden und alle anderen Team-Mitglieder sich diese Änderung und die entsprechenden Migrationsdateien dann auch zeitnah in ihr lokales Repository ziehen. Migrations-Datei erstellen ============================= Damit die Models in der Datenbank verfügbar sind, müssen sie migriert werden. Dazu erstellen wir erstmal die aktuelle Migrationsdatei für die App ``events``: .. code-block:: shell python manage.py makemigrations events Wir bekommen als Ausgabe die Meldung, dass Migatrions-Dateien erstellt wurden: .. code-block:: shell Migrations for 'events': events/migrations/0001_initial.py - Create model Category - Create model Event Migrations for 'user': user/migrations/0001_initial.py - Create model User Im Verzeichnis ``event_manager/events/migrations/`` wurde jetzt eine neue Datei angelegt, und zwar die Datei ``0001_initial.py``. Das ist die Migrationsdatei, die gerade erstellt wurde. Würden wir den ``makemigrations``-Befehl jetzt nochmal ausführen, würde die Meldung kommen, dass keine neuen Änderungen verfügbar sind. D.h., nur, wenn wir das Model ändern, erstellen wir auch eine neue Migrations-Datei. .. admonition:: migrate und makemigrations ``migrate`` und ``makemigrations`` sind die beiden Subkommandos, die nötig sind, um die Datenbank zu migrieren. ``makemigrations`` erstellt die Migrationsdatei, ``migrate`` führt anhand der erstellten Migrationsdateien die Migration(en) durch. Beide Befehle lassen sich optional auf eine konkrete App einschränken: Wenn wir also nur Migrationsdateien für die App ``events`` erstellen wollen, können wir das mit ``python manage.py makemigrations events`` bewerkstelligen. .. admonition:: Hochzählen der Migrationsdateien Bei jeder erfolgreich durchgeführten ``makemigrations``-Aktion wird eine neue Migrationsdatei erstellt. Diese Dateien haben einen numerischen Präfix (0001), der pro Erstellung inkrementiert wird. Der zweite Teil des Dateinamens wird von Django selbst generiert und bezieht sich auf die letzte Änderung im Model, zb. ``0004_alter_event_options.py``. Nun müssen wir noch die Migrationsdatei für das User-Model erstellen: .. code-block:: shell python manage.py makemigrations user Damit sind von unserer Seite alle nötigen Migrationsdatei erstellt. Wir können die Änderungen nun tatsächlich in die Datenbank schreiben. Migration durchführen ============================= Mit dem nun folgenden Befehl führen wir alle bisher noch migrierten Migrationsdateien aus. Dazu gehören auch die von den eingebauten Django-Apps selbst, denn auch diese haben wir bisher nicht migriert. .. code-block:: shell python manage.py migrate Nun wurden die Datenbank-Tabellen für die verschiedenen Apps angelegt. In der Ausgabe sehen wir auch die Migration 0001 für die App events. .. code-block:: shell Operations to perform: Apply all migrations: admin, auth, contenttypes, events, sessions, user Running migrations: Applying contenttypes.0001_initial... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0001_initial... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying auth.0012_alter_user_first_name_max_length... OK Applying user.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying events.0001_initial... OK Applying sessions.0001_initial... OK Auch das Migrieren würde sich mit ``python manage.py migrate events`` auf die Events-App eingrenzen lassen. Um zu Prüfen, wie das SQL aussieht, welches eine Migrationsdatei erstellt, kann dieser Befehl ausgeführt werden: .. code-block:: shell python manage.py sqlmigrate events 0001 Das hier gezeigte SQL ist in Abhängigkeit des in den ``settings.py`` gewählten Datenbanksystems erstellt worden. Je nach verwendetem System variiert das SQL also. Wir verwenden in diesem Buch ``sqlite3``, deshalb wird hier auch der sqlite3-Dialekt gezeigt. .. admonition:: Sqlite-Browser und SQLite-Extension Um sich die Tabellen-Struktur komfortabel anzeigen zu lassen, bietet sich für ``sqlite3`` der Sqlite-Browser an, der hier heruntergeladen werden kann: ``_ Mit dem Programm lässt sich die Datei ``event_manager/db.sqlite3`` des Projekts öffnen. Daneben gibt es zum Betrachten der Datenbank zum Beispiel für den ``VS Code Editor`` einfach zu installierende Plugins, zum Beispiel ie ``SQLite-Extension``. In der Tabelle ``django_migrations`` der sqlite3-Datenbank unseres Eventmanagers finden sich alle bisher durchgeführten Migrationen. Diese korrespondieren auch mit den Migrationsdateien der jeweiligen Apps. Man sieht überdies nicht nur die beiden von uns erstellten apps ``user`` und ``events``, sondern auch noch die django-eigenen Apps, wie ``auth`` oder ``sessions``. .. image:: /images/sqlite_browser_migrations_1.png .. admonition:: Tabula Rasa - Migrationen löschen Es kann gerade im Entwicklungsprozess passieren, dass man an einen Punkt kommt, an dem es die beste Lösung ist, die bestehenden Migrationsdateien zu löschen. Dann sollte nicht vergessen werden, die dazugehörigen Tabellen inkl. der ``django_migrations`` zu löschen. Generell gehen bei solchen Aktionen auch alle Daten verloren, was aber im Entwicklungsprozess meist weniger wichtig ist. Wir können im sqlite-Browser auch nach den Tabellen unserer Models suchen und uns die Struktur angucken. Zum Beispiel finden wir im Sqlite-Browser auch die Tabelle für die events: .. image:: /images/sqlite_browser_events_1.png .. admonition:: Tabellenname Django hat auf Basis unserer Models und dem App-Namen entsprechende Tabellenfelder erstellt. Das Default-Schema ist immer ``_``. In unserem Fall also ``events_event`` oder ``events_category.`` Falls man für sein Model einen anderen Tabellennamen haben möchte, kann man dies in der Meta-Klasse des Models anpassen. Nehmen wir an, wir würden unsere Tabelle gerne ``event_table`` nennen: .. code-block:: python class Meta: ordering = ["name"] verbose_name_plural = "Events" db_table = "event_table" weitere nützliche manage.py Commands ========================================================== * **python manage.py showmigrations** Wir können uns eine Übersicht aller existierenden Migrationsdateien ausgeben lassen. * **python manage.py check** Bevor wir eine Makemigrations durchführen, können wir mit ``check`` prüfen, ob alles in Ordnung ist und es keine Fehler in der Codebase gibt. VS Code Extension SQLite ============================= Für Visual Studio Code Nutzer empfiehlt es sich, neben dem Sqlite-Browser die ``SQLite - Extension`` von ``alexcvzz`` zu installieren. Dabei handelt es sich um ein Editor-Addon, welches sich in Visual Studio Code installieren lässt. Mit dieser Extension kann man bequem lesende Anfragen an ``sqlite3``-Datenbanken durchführen und den aktuellen Zustand der Datenbank betrachten. **Mehr zu dieser Extension hier:** ``_ Weiterführende Informationen -------------------------------------------------------------------------- * ``_ * ``_ Cookbook -------------------------------------------------------------------------- An dieser Stelle sei nochmal das Cookbook 2 zum Thema ``manage.py`` verwiesen. Dieses findet ihr im Kapitel ``Cookbooks``.