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.

Warnung

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:

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.

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.

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:

python manage.py makemigrations events

Wir bekommen als Ausgabe die Meldung, dass Migatrions-Dateien erstellt wurden:

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.

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.

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:

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.

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.

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:

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.

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: https://sqlitebrowser.org/ 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.

../_images/sqlite_browser_migrations_1.png

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:

../_images/sqlite_browser_events_1.png

Tabellenname

Django hat auf Basis unserer Models und dem App-Namen entsprechende Tabellenfelder erstellt. Das Default-Schema ist immer <APP_NAME_LOWERCASE>_<MODEL_NAME_LOWERCASE>. 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:

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: https://marketplace.visualstudio.com/items?itemName=alexcvzz.vscode-sqlite

Weiterführende Informationen

Cookbook

An dieser Stelle sei nochmal das Cookbook 2 zum Thema manage.py verwiesen. Dieses findet ihr im Kapitel Cookbooks.