.. _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``.