Problemy z typami zawartości podczas ładowania urządzenia w Django

104

Mam problem z ładowaniem urządzeń Django do mojej bazy danych MySQL z powodu konfliktów contenttypes. Najpierw próbowałem zrzucić dane tylko z mojej aplikacji w następujący sposób:

./manage.py dumpdata escola > fixture.json

ale ciągle pojawiały się problemy z brakującymi kluczami obcymi, ponieważ moja aplikacja „escola” używa tabel z innych aplikacji. Dodawałem kolejne aplikacje, aż doszedłem do tego:

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

Teraz problemem jest następujące naruszenie ograniczenia, gdy próbuję załadować dane jako urządzenie testowe:

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

Wygląda na to, że problem polega na tym, że Django próbuje dynamicznie odtworzyć typy zawartości z różnymi wartościami klucza podstawowego, które kolidują z wartościami klucza podstawowego z urządzenia. Wygląda na to, że jest to to samo, co błąd udokumentowany tutaj: http://code.djangoproject.com/ticket/7052

Problem w tym, że zalecanym obejściem jest zrzucenie aplikacji contenttypes, którą już robię !? Co daje? Jeśli to robi różnicę, mam pewne uprawnienia do modelu niestandardowego, jak udokumentowano tutaj: http://docs.djangoproject.com/en/dev/ref/models/options/#permissions

gerdemb
źródło

Odpowiedzi:

148

manage.py dumpdata --naturalużyje bardziej trwałej reprezentacji kluczy obcych. W django nazywane są one „naturalnymi kluczami”. Na przykład:

  • Permission.codename jest używany na rzecz Permission.id
  • User.username jest używany na rzecz User.id

Czytaj więcej: sekcja kluczy naturalnych w "serializowaniu obiektów django"

Kilka innych przydatnych argumentów za dumpdata :

  • --indent=4 uczynić go czytelnym dla człowieka.
  • -e sessions wykluczyć dane sesji
  • -e admin wykluczyć historię działań administratora na stronie administratora
  • -e contenttypes -e auth.Permissionwykluczyć obiekty, które są automatycznie odtwarzane ze schematu za każdym razem w trakcie syncdb. Używaj go tylko razem z, w --naturalprzeciwnym razie możesz skończyć ze źle dopasowanymi numerami identyfikacyjnymi.
Narty
źródło
1
@skyjur Dlaczego zawsze używać -e contenttypes -e auth.permissionz --natural? Po prostu próbowałem bez --naturalopcji i zadziałało. Również dokumentacja tutaj mówi , że należy użyć tej opcji, jeśli DUMPING auth.permission i contenttypes.
wlnirvana
6
@winirvana, ponieważ po rozpoczęciu od zera i wykonaniu synchronizacji, nowo utworzony ContentTypei Permissionnie ma gwarancji, że otrzyma taki sam identyfikator, jak wcześniej. Twój zrzut danych zawiera identyfikatory, które mogą odnosić się do różnych obiektów w innej bazie danych, do której będziesz ładować dane. Może to zadziałać z jednego z następujących powodów: 1) twoje dane nie miały żadnego odniesienia do tych obiektów 2) oryginalne identyfikatory Permission / ContentTypes zostały zachowane 3) twoje załadowane dane powiodły się, ale faktycznie masz uszkodzone dane z powodu obiektów odnosząc się do niewłaściwych obiektów i jeszcze o tym nie wiesz
Ski
12
Flaga --naturaljest teraz przestarzała na rzecz --natural-foreign(i --natural-primary)
frnhr
16
Ostateczne polecenie może brzmieć:manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4 > project_dump.json
Paolo
4
--naturalzostał całkowicie usunięty, a nie tylko przestarzały. Użyj --natural-foreignlub --natural-primaryzamiast.
Code-Apprentice
35

Tak, to naprawdę irytujące. Przez chwilę omijałem to, wykonując „manage.py reset” w aplikacji contenttypes przed załadowaniem urządzenia (aby pozbyć się automatycznie generowanych danych contenttypes, które różniły się od zrzuconej wersji). To zadziałało, ale w końcu miałem dość kłopotów i całkowicie porzuciłem urządzenia na rzecz prostych zrzutów SQL (oczywiście, wtedy tracisz przenośność DB).

aktualizacja - najlepszą odpowiedzią jest użycie --naturalflagi dumpdata, zgodnie z poniższą odpowiedzią. Ta flaga jeszcze nie istniała, kiedy pisałem tę odpowiedź.

Carl Meyer
źródło
3
Ja też w to wpadałem, resetowanie aplikacji contenttypes też działało. Dzięki za wskazówkę!
Beau,
Jak je zresetowałeś? W klasie przypadku testowego? Podaj mi przykład
Oleg Tarasenko
4
Nie używam urządzeń do unittestów, generalnie tworzę dane testowe za pomocą ORM w metodzie setup (), ponieważ łatwiej jest zsynchronizować się z testami. Więc nigdy nie musiałem tego robić w klasie TestCase, chociaż jestem pewien, że jeśli zaglądasz do kodu klasy TestCase Django, możesz dowiedzieć się, jak wykonać resetowanie po synchronizacji, a przed załadowaniem urządzenia w podklasie. Dla mnie było to po prostu „./manage.py reset contenttypes” w skrypcie basha przed „./manage.py loaddata my_fixture”.
Carl Meyer
32

Spróbuj pominąć typy zawartości podczas tworzenia urządzenia:

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

U mnie zadziałało w podobnej sytuacji w przypadku testów jednostkowych, Twój wgląd w typy zawartości naprawdę pomógł!

Evgeny
źródło
31

Odpowiedzi tutaj wszystkie stare ... Od 2017 roku najlepszą odpowiedzią jest:

manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4
Witaj świecie
źródło
11

Nie używałem MySQL, ale zamiast tego importowałem niektóre dane z aktywnego serwera do sqlite. Wyczyszczenie contenttypesdanych aplikacji przed wykonaniem loaddatazałatwiło sprawę:

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

I wtedy

python manage.py loaddata data.json
MadeOfAir
źródło
django.core.exceptions.ImproperlyConfigured: zażądano ustawienia INSTALLED_APPS, ale ustawienia nie są skonfigurowane. Musisz zdefiniować zmienną środowiskową DJANGO_SETTINGS_MODULE lub wywołać settings.configure () przed uzyskaniem dostępu do ustawień.
Barney
Prawdopodobnie najlepiej działałoby w ramach uchwytu niestandardowego polecenia zarządzania.
Barney
10

Rozwiązałem ten problem w moich przypadkach testowych, resetując aplikację contenttypes z testu jednostkowego przed załadowaniem pliku zrzutu. Carl zasugerował to już przy użyciu manage.pypolecenia, a ja robię to samo tylko call_commandmetodą:

>>> 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)

Moje full_test_data.jsonurządzenie zawiera zrzut aplikacji contenttypes, który odpowiada pozostałym danym testowym. Resetowanie aplikacji przed załadowaniem zapobiega zduplikowaniu klucza IntegrityError.

Jesse L.
źródło
7
python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth.Permission --exclude=admin.logentry --exclude=sessions.session --indent 4 > initial_data.json

To działa dla mnie. Tutaj wykluczam wszystko, co dotyczy rzeczywistych modeli.

  • Jeśli zobaczysz inny model niż modele, które utworzyłeś, możesz je bezpiecznie wykluczyć. Jedną z wad tego podejścia jest utrata danych dziennika, a także danych uwierzytelniania.
Ojas Kale
źródło
6

Aby przedstawić dowolny klucz obcy i relacje „wiele do wielu”, należy użyć kluczy naturalnych. Ponadto dobrym pomysłem może być wykluczenie sessiontabeli w sessionsaplikacji i logentrytabeli w adminaplikacji.

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

Zgodnie z dokumentacją Django , --naturalzostał wycofany w wersji 1.7, więc --natural-foreignzamiast tego należy użyć tej opcji .

Możesz również pominąć klucz podstawowy w zserializowanych danych tego obiektu, ponieważ można go obliczyć podczas deserializacji, przekazując --natural-primaryflagę.

python manage.py dumpdata --natural-foreign --natural-primary --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json
lmiguelvargasf
źródło
2
./manage.py dumpdata app.Model --natural-foreign

ulegnie zmianie

  "content_type": 123

do

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

A urządzenie na TestCaserazie działa

Daniil Mashkin
źródło
2

Django 2.2.5

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

pomogło mi

Igor Z
źródło
Pojawi się problem, gdy loaddata, może być niezgodny z typem zawartości w nowej bazie danych
yang zhou
1

Podam inną możliwą odpowiedź, którą właśnie odkryłem. Może to pomoże OP, może pomoże komuś innemu.

Mam tabelę relacji wiele do wielu. Ma klucz podstawowy i dwa klucze obce do innych tabel. Stwierdziłem, że jeśli mam wpis w urządzeniu, którego dwa klucze obce są takie same jak inny wpis już w tablicy z innym pakietem, zakończy się niepowodzeniem. Tabele relacji M2M mają „unikalne razem” dla dwóch kluczy obcych.

Tak więc, jeśli jest to relacja M2M, która się zrywa, spójrz na dodawane klucze obce, spójrz na swoją bazę danych, aby zobaczyć, czy ta para FK jest już wymieniona pod inną PK.

orblivion
źródło
1

To naprawdę irytujące… Za każdym razem mnie to ugryza.

Próbowałem zrzucić dane z --exclude contenttypes i --natural, zawsze mam problemy.

To, co działa najlepiej, to po prostu wykonanie pliku truncate table django_content_type; po synchronizacji, a NASTĘPNIE załadowanie danych.

Oczywiście dla automatycznego ładowania initial_data.json jesteś fallball.

h3.
źródło
Dla mnie obcięcie tabeli przed załadowaniem danych powoduje po prostu różne błędy. Nie ma szczęścia z tą techniką.
shacker
1

Czasami napotkałem podobny błąd. Okazało się, że próbowałem załadować urządzenia przed utworzeniem niezbędnych tabel. Więc zrobiłem:

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

I działało jak urok

James Wanderi
źródło
0

W moim przypadku zrzuciłem dane z auth(./manage.py dumpddata auth > fixtures/auth.json ), aby użyć urządzenia do celów testowych.

Rozwój był kontynuowany i usunąłem większość modeli, które zdefiniowałem w models.py i wtedy zacząłem widzieć ten irytujący problem.

Moim rozwiązaniem było ponowne zregenerowanie urządzenia auth.json. Ten usunął wiele wpisów auth.permissionzwiązanych ze starymi modelami, które miałem.

Pablo Castellano
źródło
0

Próbowałem każdej metody z góry, nic nie działało dla mnie. Muszę wykluczyć pełny model uwierzytelniania i działa dobrze.

python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth --exclude=admin.logentry --exclude=sessions.session --indent 4 > live.json
Chandra Shekhar Pandey
źródło