Problèmes avec les types de contenu lors du chargement d'un appareil dans Django

104

J'ai du mal à charger les fixtures Django dans ma base de données MySQL en raison de conflits de types de contenu. J'ai d'abord essayé de vider les données de mon application uniquement comme ceci:

./manage.py dumpdata escola > fixture.json

mais j'ai continué à avoir des problèmes de clé étrangère manquante, parce que mon application "escola" utilise des tables d'autres applications. J'ai continué à ajouter des applications supplémentaires jusqu'à ce que j'arrive à ceci:

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

Maintenant, le problème est la violation de contrainte suivante lorsque j'essaie de charger les données en tant que montage de test:

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

Il semble que le problème soit que Django essaie de recréer dynamiquement des types de contenu avec différentes valeurs de clé primaire qui sont en conflit avec les valeurs de clé primaire de l'appareil. Cela semble être le même que le bogue documenté ici: http://code.djangoproject.com/ticket/7052

Le problème est que la solution de contournement recommandée consiste à vider l'application contenttypes, ce que je fais déjà!? Ce qui donne? Si cela fait une différence, j'ai des autorisations de modèle personnalisées telles que documentées ici: http://docs.djangoproject.com/en/dev/ref/models/options/#permissions

Gerdemb
la source

Réponses:

148

manage.py dumpdata --naturalutilisera une représentation plus durable des clés étrangères. En django, elles sont appelées "clés naturelles". Par exemple:

  • Permission.codename est utilisé en faveur de Permission.id
  • User.username est utilisé en faveur de User.id

En savoir plus: section sur les clés naturelles dans "sérialiser des objets django"

Quelques autres arguments utiles pour dumpdata:

  • --indent=4 le rendre lisible par l'homme.
  • -e sessions exclure les données de session
  • -e admin exclure l'historique des actions d'administration sur le site d'administration
  • -e contenttypes -e auth.Permissionexclure les objets qui sont recréés automatiquement du schéma à chaque fois pendant syncdb. Utilisez-le uniquement avec, --naturalsinon vous pourriez vous retrouver avec des numéros d'identification mal alignés.
Ski
la source
1
@skyjur Pourquoi toujours utiliser -e contenttypes -e auth.permissionavec --natural? J'ai juste essayé sans l' --naturaloption et cela a fonctionné. La documentation ici indique également qu'il faut utiliser cette option si DUMPING auth.permission et contenttypes.
wlnirvana
6
@winirvana parce qu'après avoir recommencé à zéro et faire syncdb, nouvellement créés ContentTypeet Permissionne sont pas garantis d'obtenir le même identifiant qu'avant. Votre vidage de données contient des identifiants qui peuvent référencer différents objets sur une base de données plutôt que dans laquelle vous allez charger des données. Cela pourrait fonctionner pour vous pour l'une de ces raisons: 1) vos données ne faisaient aucune référence à ces objets 2) les identifiants originaux de Permission / ContentTypes ont été préservés 3) vos données de chargement ont réussi mais vous avez en fait des données corrompues en raison d'objets se référant à de mauvais objets et vous ne le savez pas encore
Ski
12
Le drapeau --naturalest désormais obsolète au profit de --natural-foreign(et --natural-primary)
Frnhr
16
La commande finale pourrait être:manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4 > project_dump.json
Paolo
4
--naturala maintenant été complètement supprimé, pas seulement obsolète. Utilisez --natural-foreignou à la --natural-primaryplace.
Code-Apprentice
35

Oui, c'est vraiment irritant. Pendant un certain temps, j'ai contourné ce problème en effectuant une «réinitialisation manage.py» sur l'application contenttypes avant de charger l'appareil (pour me débarrasser des données contenttypes générées automatiquement qui différaient de la version sauvegardée). Cela a fonctionné, mais finalement je suis tombé malade des tracas et des montages abandonnés entièrement en faveur de vidages SQL directs (bien sûr, vous perdez la portabilité de la base de données).

mise à jour - la meilleure réponse est d'utiliser le --naturaldrapeau pour dumpdata, comme indiqué dans une réponse ci-dessous. Ce drapeau n'existait pas encore lorsque j'ai écrit cette réponse.

Carl Meyer
la source
3
J'étais en train de rencontrer cela aussi, la réinitialisation de l'application contenttypes a également fonctionné pour moi. Merci pour le conseil!
Beau
Comment les avez-vous réinitialisés? En classe de cas de test? Donnez-moi un exemple s'il vous plaît
Oleg Tarasenko
4
Je n'utilise pas de fixtures pour les tests unitaires, je crée généralement des données de test en utilisant l'ORM dans une méthode setup () car il est plus facile de rester synchronisé avec les tests. Je n'ai donc jamais eu à faire cela dans une classe TestCase, même si je suis sûr que si vous fouillez dans le code de la classe TestCase de Django, vous pourriez trouver comment faire une réinitialisation après syncdb et avant le chargement de l'appareil dans une sous-classe. Pour moi, c'était juste "./manage.py reset contenttypes" dans un script bash avant "./manage.py loaddata my_fixture".
Carl Meyer
32

Essayez d'ignorer les types de contenu lors de la création d'un appareil:

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

Cela a fonctionné pour moi dans une situation similaire pour les tests unitaires, votre compréhension des types de contenu m'a vraiment aidé!

Evgeny
la source
31

Les réponses ici toutes anciennes ... À partir de 2017, la meilleure réponse est:

manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4
Bonjour le monde
la source
11

Je n'utilisais pas MySQL mais importais plutôt des données d'un serveur live dans sqlite. Effacer les contenttypesdonnées de l' application avant de procéder a loaddatafait l'affaire:

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

Puis

python manage.py loaddata data.json
MadeOfAir
la source
django.core.exceptions.ImproperlyConfigured: paramètre demandé INSTALLED_APPS, mais les paramètres ne sont pas configurés. Vous devez soit définir la variable d'environnement DJANGO_SETTINGS_MODULE, soit appeler settings.configure () avant d'accéder aux paramètres.
Barney
Cela fonctionnerait probablement mieux dans le cadre d'une commande de gestion personnalisée.
Barney
10

J'ai résolu ce problème dans mes scénarios de test en réinitialisant l'application contenttypes à partir du test unitaire avant de charger mon fichier de vidage. Carl a déjà suggéré cela en utilisant la manage.pycommande et je fais la même chose uniquement en utilisant la call_commandméthode:

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

Mon full_test_data.jsonappareil contient le vidage de l'application contenttypes qui correspond au reste des données de test. En réinitialisant l'application avant le chargement, il empêche la clé en double IntegrityError.

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

Cela fonctionne pour moi. Ici, j'exclus tout ce qui concerne les modèles réels.

  • Si vous voyez un autre modèle que les modèles que vous avez créés, vous pouvez les exclure en toute sécurité. Un inconvénient de cette approche est que vous perdez des données de journal ainsi que des données d'authentification.
Ojas Kale
la source
6

Vous devez utiliser des clés naturelles pour représenter les clés étrangères et les relations plusieurs-à-plusieurs. De plus, il peut être judicieux d'exclure le sessiontableau dans l' sessionsapplication et le logentrytableau dans l' adminapplication.

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

Selon la documentation de Django , --naturala été déconseillée dans la version 1.7, donc l'option --natural-foreigndoit être utilisée à la place.

Vous pouvez également omettre la clé primaire dans les données sérialisées de cet objet car elle peut être calculée lors de la désérialisation en passant l' --natural-primaryindicateur.

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

changera

  "content_type": 123

à

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

Et le luminaire fonctionne pour l' TestCaseinstant

Daniil Mashkin
la source
2

Django 2.2.5

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

ça m'a aidé

Igor Z
la source
Cela posera un problème lors du chargement des données, peut-être une incompatibilité avec le type de contenu dans la nouvelle base de données
yang zhou
1

Je vais donner une autre réponse possible que je viens de trouver. Peut-être que cela aidera l'OP, peut-être que cela aidera quelqu'un d'autre.

J'ai une table de relations plusieurs-à-plusieurs. Il a une clé primaire et les deux clés étrangères vers les autres tables. J'ai trouvé que si j'ai une entrée dans l'appareil dont les deux clés étrangères sont les mêmes qu'une autre entrée déjà dans le tableau avec un autre pk , cela échouera. Les tables de relations M2M ont un «ensemble unique» pour les deux clés étrangères.

Donc, si c'est une relation M2M qui se rompt, regardez les clés étrangères qu'elle ajoute, regardez votre base de données pour voir si cette paire de FK est déjà répertoriée sous un PK différent.

orblivion
la source
1

C'est vraiment, vraiment ennuyeux ... Je suis mordu par ça à chaque fois.

J'ai essayé de vider des données avec --exclude contenttypes et --natural, j'ai toujours des problèmes.

Ce qui fonctionne le mieux pour moi est simplement de faire un truncate table django_content_type; après la synchronisation et ALORS charger les données.

Bien sûr, pour le chargement automatique initial_data.json, vous êtes tombé en panne.

h3.
la source
Pour moi, tronquer la table avant loaddata ne cause que des erreurs différentes. Pas de chance avec cette technique.
shacker
1

J'avais rencontré une erreur similaire il y a parfois. Il s'est avéré que j'essayais de charger les appareils avant de créer les tables nécessaires. Alors j'ai fait:

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

Et ça a fonctionné comme un charme

James Wanderi
la source
0

Dans mon cas, j'avais vidé les données de auth(./manage.py dumpddata auth > fixtures/auth.json ) pour utiliser l'appareil à des fins de test.

Le développement s'est poursuivi et j'ai supprimé la plupart des modèles que j'avais définis dans models.py et c'est à ce moment-là que j'ai commencé à voir ce problème ennuyeux.

Ma solution était de régénérer à nouveau l'appareil auth.json. Celui-ci avait supprimé beaucoup d'entrées auth.permissionliées aux anciens modèles que j'avais.

Pablo Castellano
la source
0

J'ai essayé toutes les méthodes d'en haut, rien n'a fonctionné pour moi. Je dois exclure le modèle d'authentification complet et fonctionne très bien.

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