Django 1.8: Erstellen Sie erste Migrationen für ein vorhandenes Schema

73

Ich habe ein Django 1.8-Projekt gestartet, das das Migrationssystem verwendet.
Irgendwie wurde es auf dem Weg chaotisch, also habe ich die Migrationsordner und -tabellen aus der Datenbank gelöscht und jetzt versuche ich, sie ohne Erfolg zu rekonstruieren.

Ich habe drei Apps (3 models.pyDateien) und die Modelle spiegeln die Tabellen genau wider!

Der beste Ansatz, den ich bisher gefunden habe, war:

  1. Löschen Sie alle migrationsOrdner. Erledigt!
  2. Löschen Sie alles aus der django_migrationsTabelle. Erledigt!
  3. Führen Sie python manage.py makemigrations --empty <app>für jede App. Erledigt!
  4. Ausführen python manage.py migrate --fake. Erledigt! (obwohl es nur funktioniert, wenn ich es nach jedem makemigrationsBefehl ausführe .

Jetzt füge ich ein neues Feld hinzu, führe den makemigrationsBefehl aus und erhalte die folgende Fehlermeldung:
django.db.utils.OperationalError: (1054, "Unknown column 'accounts_plan.max_item_size' in 'field list'")

Ich habe STUNDEN auf dieses Ding gebrannt. Wie kann ich die Migrationen initialisieren, damit ich jedes Mal ohne Migrationsunterbrechungen weiterarbeiten kann?

Warum ist es so kompliziert? Warum gibt es keinen einfachen Einzeiler initiate_migrations_from_schema?

EDIT:
Jetzt wird es noch schlimmer. Ich habe die django_migrationsTabelle abgeschnitten und den gesamten migrationsOrdner gelöscht .
Jetzt versuche ich auszuführen python manage.py migrate --fake-initial(etwas, das ich in den DEV-Dokumenten gefunden habe), nur damit alle 'internen' Apps von Django (Authentifizierung, Sitzung usw.) eingerichtet werden und ich bekomme :
(1054, "Unknown column 'name' in 'django_content_type'").
Diese "Spalte" ist keine echte Spalte. Es ist eine @propertyin Djangos contenttypesApp definierte. WAS GEHT HIER VOR SICH? Warum wird die nameEigenschaft als echte Spalte identifiziert ?

user1102018
quelle
Haben Sie die eigentliche Tabelle gelöscht? Oder hast du es einfach geleert?
Rnevius
Ich habe es gerade geleert:delete from django_migrations
user1102018
Sie müssen wahrscheinlich alle Tabellen
löschen
Ich habe Daten in diesen Tabellen und möchte sie nicht löschen. Ich weiß, dass ich sie sichern, löschen, erstellen und wiederherstellen kann. Aber ich habe 10 Tische und das möchte ich nicht. Ich möchte nur die Migrationen initiieren.
user1102018

Antworten:

167

Endlich hat es funktioniert, obwohl ich nicht weiß warum und ich hoffe, dass es in Zukunft funktionieren wird.
Nach zahlreichen Versuchen und Durchlaufen der Entwicklungsseite von Django ( Link ).
Hier sind die Schritte (für alle, die auf dieses Problem stoßen):

  1. Leeren Sie den django_migrationsTisch:delete from django_migrations;
  2. Löschen Sie für jede App ihren migrationsOrdner:rm -rf <app>/migrations/
  3. Setzen Sie die Migrationen für die "integrierten" Apps zurück: python manage.py migrate --fake
  4. Für jeden App-Lauf : python manage.py makemigrations <app>. Achten Sie auf Abhängigkeiten (Modelle mit ForeignKey sollten nach dem übergeordneten Modell ausgeführt werden).
  5. Schließlich: python manage.py migrate --fake-initial

Danach habe ich den letzten Befehl ohne --fake-initialFlag ausgeführt, nur um sicherzugehen.

Jetzt funktioniert alles und ich kann das Migrationssystem normal verwenden.

Ich bin sicher, dass ich nicht der einzige bin, der auf dieses Problem stößt. Es muss besser dokumentiert und sogar vereinfacht werden.

Update für Django 1.9-Benutzer:
Ich hatte dieses Szenario erneut mit einem Django 1.9.4 und Schritt 5 schlug fehl.
Alles , was ich hatte , ist zu ersetzen zu tun --fake-initialmit --fakeihm arbeiten zu lassen.

user1102018
quelle
Ich komme jedoch RuntimeError: Error creating new content types. Please make sure contenttypes is migrated before trying to migrate apps individually.zum letzten Schritt für Django 1.8.3. Weißt du, warum?
Ericn
1
@eric versuche python manage.py migrate contenttypesvor dem letzten Schritt zu laufen .
Azalee
9
sollte unter "Zurücksetzen von Migrationen" dokumentiert werden. vielleicht sogar ein reset_migrations Management-Befehl
Adam Spence
Vielen Dank dafür, ich konnte nicht finden, wie ich das woanders machen soll ... Das sollte wirklich dokumentiert werden.
Hayze
Musste aus django_migrations löschen; Führen Sie dann python manage.py migrate aus. und es hat funktioniert.
Stryker
3

django ..., 1,8, 1,9, ...

Was Sie erreichen möchten, ist, vorhandene Migrationen zu unterdrücken und diese zu ersetzen.

So machen Sie es richtig, ohne beim Freigeben einen Befehl zu verwenden (ein Fall ohne Auswirkungen auf Datenbank und Mitarbeiter).

  1. Entfernen Sie für jede App den Migrationsordner: mv <app>/migrations/ <app>/migrationsOLD/

  2. Für jeden App-Lauf : python manage.py makemigrations <app>.

  3. Passen Sie jede neue Migration an:

    • Wenn Sie eine komplexe App oder mehrere Apps und verwandte Modelle zwischen sich haben, um Folgendes zu vermeiden CircularDependencyErroroder ValueError: Unhandled pending operations for models:

      Bereiten Sie die zweite leere Migration in vor <app> 0002_initial2.py(setzen Sie dort die Abhängigkeit zu app_other::0001_initial.pyund <app>:: 0001_initial.py- alle ForeignKey, M2M, die sich auf Modelle beziehen, die im Migrationsschritt 0001 in anderen Apps erstellt wurden).

      Alles muss in Ordnung sein - manchmal sind mehr Migrationen erforderlich, um sich vorzubereiten. Achten Sie dependencieshier bei jeder Migration auf die Attribute.

    • Achten Sie auf die Anfangswerte - überprüfen Sie alle RunPythonAktionen von migrationsOLDund kopieren Sie den Code bei Bedarf in die neue Erstmigration.

    • (optional für --fake-initial) initial=TrueZu allen neuen Migrationsklassen hinzufügen (auch 0002, falls hinzugefügt).

    • In replacesAttribute in neuer Migration Klasse. (wie eigene Gewohnheit a squashmigrations). Legen Sie dort alle alten Migrationen von<app>
  4. Überprüfen Sie alles mit makemigrations.

    behaupten "Keine Änderungen erkannt"

  5. Überprüfen Sie, ob migrate -lüberall [x] angezeigt wird

    behaupten ähnlich:

    [X] 0001_initial

    [X] 0002_initial2 (102 gequetschte Migrationen)

Beispiel:

Für alte:

0001_initial.py
0002_auto.py
...
0103_auto.py

bereiten:

0001_initial.py
0002_initial2.py  (optional but sometimes required to satisfy dependency)

und replaceszum letzten hinzufügen (0002 hier, kann 0001 sein):

replaces = [(b'<app>', '0002_auto.py'), ..., (b'<app>', '0103_auto.py')]

0001_initial.py sollte genauso benannt werden wie die alte.

0002_initial2.py ist neu, ersetzt jedoch alte Migrationen, sodass Django sie als geladen behandelt.

Sławomir Lenart
quelle
2

Ich bin auf dieses Szenario gestoßen, musste aber nie die Datenbank löschen, um es zu lösen. Normalerweise lösche ich den Migrationsordner aus der App und entferne die Migrationseinträge aus der Datenbank.

Ich würde versuchen, Migrationen einzeln durchzuführen. Wenn sich eine der Apps auf andere Tabellen stützt, fügen Sie diese offensichtlich zuletzt hinzu.

Außerdem starte ich normalerweise nur python manage.py makemigrations und dann nur python manage.py migrate. Selbst bei der anfänglichen Migration sollte es mit Django 1.7 und 1.8 gut funktionieren.

Chris Hawkes
quelle
4
Versuchte das, und es funktioniert offensichtlich nicht, da der migrateBefehl versucht, die Tabellen (die bereits vorhanden sind) zu erstellen ...
user1102018
können Sie versuchen >> Python Makemigrations yourApp --initial
Chris Hawkes
Versuchte es, bekam:manage.py makemigrations: error: unrecognized arguments: --initial
user1102018
0

Wenn Sie Router verwenden, liegt dort möglicherweise ein Problem vor. Überprüfen Sie die Methode, allow_migrateob sie ordnungsgemäß ausgeführt wurde routers.py. Versuchen Sie, den Rückgabewert immer so einzustellen, dass Trueer das Problem behebt.

def allow_migrate(self, db, app_label, model_name=None, **hints):
    return True
AmirM
quelle