Probleme mit Inhaltstypen beim Laden eines Geräts in Django

104

Ich habe Probleme beim Laden von Django-Fixtures in meine MySQL-Datenbank aufgrund von Konflikten mit Inhaltstypen. Zuerst habe ich versucht, die Daten nur von meiner App wie folgt zu sichern:

./manage.py dumpdata escola > fixture.json

Es fehlten jedoch immer wieder Probleme mit Fremdschlüsseln, da meine App "escola" Tabellen aus anderen Anwendungen verwendet. Ich habe weitere Apps hinzugefügt, bis ich dazu kam:

./manage.py dumpdata contenttypes auth escola > fixture.json

Das Problem ist nun die folgende Einschränkungsverletzung, wenn ich versuche, die Daten als Testgerät zu laden:

IntegrityError: (1062, "Duplicate entry 'escola-t23aluno' for key 2")

Es scheint, dass das Problem darin besteht, dass Django versucht, Inhaltstypen mit verschiedenen Primärschlüsselwerten, die mit den Primärschlüsselwerten des Geräts in Konflikt stehen, dynamisch neu zu erstellen. Dies scheint der gleiche zu sein wie der hier dokumentierte Fehler: http://code.djangoproject.com/ticket/7052

Das Problem ist, dass die empfohlene Problemumgehung darin besteht, die Contenttypes-App zu sichern, die ich bereits mache!? Was gibt? Wenn es einen Unterschied macht, habe ich einige benutzerdefinierte Modellberechtigungen, wie hier dokumentiert: http://docs.djangoproject.com/de/dev/ref/models/options/#permissions

gerdemb
quelle

Antworten:

148

manage.py dumpdata --naturalverwendet eine dauerhaftere Darstellung von Fremdschlüsseln. Im Django werden sie "natürliche Schlüssel" genannt. Beispielsweise:

  • Permission.codename wird zugunsten von verwendet Permission.id
  • User.username wird zugunsten von verwendet User.id

Lesen Sie mehr: Abschnitt über natürliche Schlüssel unter "Serialisieren von Django-Objekten"

Einige andere nützliche Argumente für dumpdata:

  • --indent=4 mach es menschlich lesbar.
  • -e sessions Sitzungsdaten ausschließen
  • -e admin Verlauf von Administratoraktionen auf der Administrator-Site ausschließen
  • -e contenttypes -e auth.PermissionObjekte ausschließen, die jedes Mal automatisch aus dem Schema neu erstellt werden syncdb. Verwenden Sie es nur zusammen mit --naturaloder Sie erhalten möglicherweise schlecht ausgerichtete ID-Nummern.
Ski
quelle
1
@skyjur Warum immer -e contenttypes -e auth.permissionmit verwenden --natural? Ich habe es nur ohne die --naturalOption versucht und es hat funktioniert. Auch die Dokumentation hier sagt, dass man diese Option verwenden sollte, wenn DUMPING auth.permission und contenttypes.
Wlnirvana
6
@winirvana, weil, nachdem Sie von vorne angefangen und syncdb gemacht haben, neu erstellt wurden ContentTypeund Permissionnicht garantiert werden, dass sie die gleiche ID wie zuvor erhalten. Ihr Datendump enthält IDs, die möglicherweise auf verschiedene Objekte in einer anderen Datenbank verweisen, in die Sie Daten laden. Dies könnte aus einem der folgenden Gründe für Sie funktionieren: 1) Ihre Daten hatten keinen Verweis auf diese Objekte. 2) Die ursprünglichen IDs von Permission / ContentTypes wurden beibehalten. 3) Ihre Ladedaten waren erfolgreich, aber Sie haben tatsächlich beschädigte Daten aufgrund von Objekten unter Bezugnahme auf falsche Objekte und Sie wissen noch nichts darüber
Ski
12
Flagge --naturalist jetzt zugunsten von --natural-foreign(und --natural-primary) veraltet
am
16
Letzter Befehl könnte sein:manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4 > project_dump.json
Paolo
4
--naturalwurde jetzt komplett entfernt, nicht nur veraltet. Verwenden Sie --natural-foreignoder --natural-primarystattdessen.
Code-Apprentice
35

Ja, das ist wirklich irritierend. Eine Weile habe ich es umgangen, indem ich vor dem Laden des Fixtures ein "manage.py reset" für die Contenttypes-App durchgeführt habe (um die automatisch generierten Contenttypes-Daten zu entfernen, die sich von der gedumpten Version unterschieden). Das hat funktioniert, aber irgendwann habe ich die Probleme satt und die Fixtures ganz zugunsten von reinen SQL-Dumps aufgegeben (dann verlieren Sie natürlich die DB-Portabilität).

Update - Die beste Antwort ist, das --naturalFlag zu verwenden dumpdata, wie in einer Antwort unten angegeben. Diese Flagge existierte noch nicht, als ich diese Antwort schrieb.

Carl Meyer
quelle
3
Ich bin auch darauf gestoßen und habe das Zurücksetzen der Contenttypes-App auch für mich funktioniert. Danke für den Tipp!
Beau
Wie haben Sie sie zurückgesetzt? In der Testfallklasse? Geben Sie mir bitte ein Beispiel
Oleg Tarasenko
4
Ich verwende keine Fixtures für Unittests. Im Allgemeinen erstelle ich Testdaten mithilfe des ORM in einer setup () -Methode, da es einfacher ist, mit den Tests synchron zu bleiben. Ich musste dies also nie in einer TestCase-Klasse tun, obwohl ich mir sicher bin, dass Sie, wenn Sie im Code für Djangos TestCase-Klasse stöbern, herausfinden können, wie ein Reset nach der Synchronisierung und vor dem Laden des Geräts in einer Unterklasse durchgeführt werden kann. Für mich war es nur "./manage.py reset contenttypes" in einem Bash-Skript vor "./manage.py loaddata my_fixture".
Carl Meyer
32

Versuchen Sie, beim Erstellen eines Geräts Inhaltstypen zu überspringen:

./manage.py dumpdata --exclude contenttypes > fixture.json

Es hat bei mir in einer ähnlichen Situation für Unit-Tests funktioniert, Ihr Einblick in die Inhaltstypen hat wirklich geholfen!

Evgeny
quelle
31

Die Antworten hier sind alle alt ... Ab 2017 ist die beste Antwort:

manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4
Hallo Welt
quelle
11

Ich habe nicht MySQL verwendet, sondern einige Daten von einem Live-Server in SQLite importiert. Das Löschen der contenttypesApp-Daten vor dem Ausführen loaddatahat den folgenden Trick ausgeführt:

from django.contrib.contenttypes.models import ContentType
ContentType.objects.all().delete()
quit()

Und dann

python manage.py loaddata data.json
MadeOfAir
quelle
django.core.exceptions.ImproperlyConfigured: Angeforderte Einstellung INSTALLED_APPS, aber die Einstellungen sind nicht konfiguriert. Sie müssen entweder die Umgebungsvariable DJANGO_SETTINGS_MODULE definieren oder settings.configure () aufrufen, bevor Sie auf Einstellungen zugreifen können.
Barney
Es würde wahrscheinlich am besten im Handle eines benutzerdefinierten Verwaltungsbefehls funktionieren.
Barney
10

Ich habe dieses Problem in meinen Testfällen behoben, indem ich die Contenttypes-App vor dem Laden meiner Dump-Datei aus dem Unit-Test zurückgesetzt habe. Carl schlug dies bereits mit dem manage.pyBefehl vor und ich mache dasselbe nur mit der call_commandMethode:

>>> from django.core import management
>>> management.call_command("flush", verbosity=0, interactive=False)
>>> management.call_command("reset", "contenttypes", verbosity=0, interactive=False)
>>> management.call_command("loaddata", "full_test_data.json", verbosity=0)

Mein full_test_data.jsonGerät enthält den Content-Typ-App-Dump, der den restlichen Testdaten entspricht. Durch Zurücksetzen der App vor dem Laden wird der doppelte Schlüssel verhindert IntegrityError.

Jesse L.
quelle
7
python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth.Permission --exclude=admin.logentry --exclude=sessions.session --indent 4 > initial_data.json

Das funktioniert bei mir. Hier schließe ich alles aus, was den eigentlichen Modellen entspricht.

  • Wenn Sie ein anderes Modell als die von Ihnen erstellten Modelle sehen, können Sie diese sicher ausschließen. Ein Nachteil dieses Ansatzes besteht darin, dass Sie sowohl Protokolldaten als auch Authentifizierungsdaten verlieren.
Ojas Grünkohl
quelle
6

Sie müssen natürliche Schlüssel verwenden, um jeden Fremdschlüssel und viele-zu-viele-Beziehungen darzustellen. Darüber hinaus ist es möglicherweise eine gute Idee, die sessionTabelle in der sessionsApp und die logentryTabelle in der adminApp auszuschließen .

Django 1.7+

python manage.py dumpdata --natural-foreign --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json

Django <1,7

python manage.py dumpdata --natural --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json

Gemäß der Dokumentation Django , --naturalwurde in der Version 1.7, veraltet , so dass die Option --natural-foreignsollte stattdessen verwendet werden.

Sie können den Primärschlüssel auch in den serialisierten Daten dieses Objekts weglassen, da er während der Deserialisierung durch Übergeben des --natural-primaryFlags berechnet werden kann .

python manage.py dumpdata --natural-foreign --natural-primary --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json
lmiguelvargasf
quelle
2
./manage.py dumpdata app.Model --natural-foreign

wird sich verändern

  "content_type": 123

zu

  "content_type": [
    "app_label",
    "model"
  ],

Und das Gerät funktioniert TestCasevorerst

Daniil Mashkin
quelle
2

Django 2.2.5

python manage.py dumpdata --exclude=contenttypes > datadump.json

Es hat mir geholfen

Igor Z.
quelle
Es wird Probleme beim Laden von Daten aufwerfen, möglicherweise nicht mit dem Inhaltstyp in der neuen Datenbank übereinstimmen
Yang Zhou
1

Ich werde eine andere mögliche Antwort geben, die ich gerade herausgefunden habe. Vielleicht hilft es dem OP, vielleicht hilft es jemand anderem.

Ich habe eine Viele-zu-Viele-Beziehungstabelle. Es hat einen Primärschlüssel und die beiden Fremdschlüssel zu den anderen Tabellen. Ich habe festgestellt, dass ein Eintrag im Gerät, dessen zwei Fremdschlüssel mit einem anderen Eintrag in der Tabelle mit einem anderen Paket identisch sind, fehlschlägt. M2M-Beziehungstabellen haben ein "eindeutiges Zusammen" für die beiden Fremdschlüssel.

Wenn es sich also um eine M2M-Beziehung handelt, die unterbrochen wird, überprüfen Sie die hinzugefügten Fremdschlüssel und sehen Sie in Ihrer Datenbank nach, ob dieses FK-Paar bereits unter einer anderen PK aufgeführt ist.

Orblivion
quelle
1

Es ist wirklich sehr, sehr nervig. Ich werde jedes Mal davon gebissen.

Ich habe versucht, Daten mit --exclude contenttypes und --natural zu sichern, ich bekomme immer Probleme ..

Was für mich am besten funktioniert, ist einfach eine truncate table django_content_type;nach der Synchronisierung durchzuführen und dann die Daten zu laden.

Natürlich sind Sie für das automatische Laden von initial_data.json Fallball.

h3.
quelle
Das Abschneiden der Tabelle vor dem Laden von Daten führt für mich nur zu unterschiedlichen Fehlern. Kein Glück mit dieser Technik.
Shacker
1

Ich hatte vor manchmal einen ähnlichen Fehler festgestellt. Es stellte sich heraus, dass ich versuchte, die Fixtures zu laden, bevor ich die erforderlichen Tabellen erstellte. So tat ich:

$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py loaddata fixtures/initial_data.json

Und es hat wie ein Zauber funktioniert

James Wanderi
quelle
0

In meinem Fall hatte ich die Daten von auth( ./manage.py dumpddata auth > fixtures/auth.json) ausgegeben, um das Gerät zu Testzwecken zu verwenden.

Die Entwicklung wurde fortgesetzt und ich entfernte die meisten Modelle, in denen ich definiert hatte, models.pyund zu diesem Zeitpunkt bemerkte ich dieses ärgerliche Problem.

Meine Lösung bestand darin, das auth.json-Gerät erneut zu generieren. Dieser hatte viele Einträge entfernt auth.permission, die sich auf die alten Modelle bezogen, die ich hatte.

Pablo Castellano
quelle
0

Ich habe jede Methode von oben ausprobiert. Nichts hat bei mir funktioniert. Ich muss das komplette Auth-Modell ausschließen und funktioniert einwandfrei.

python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth --exclude=admin.logentry --exclude=sessions.session --indent 4 > live.json
Chandra Shekhar Pandey
quelle