Problemas con los tipos de contenido al cargar un dispositivo en Django

104

Tengo problemas para cargar los accesorios de Django en mi base de datos MySQL debido a conflictos de tipos de contenido. Primero intenté descargar los datos solo de mi aplicación de esta manera:

./manage.py dumpdata escola > fixture.json

pero seguía teniendo problemas de claves foráneas faltantes, porque mi aplicación "escola" usa tablas de otras aplicaciones. Seguí agregando aplicaciones adicionales hasta que llegué a esto:

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

Ahora el problema es la siguiente violación de la restricción cuando trato de cargar los datos como un dispositivo de prueba:

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

Parece que el problema es que Django está intentando recrear dinámicamente tipos de contenido con diferentes valores de clave primaria que entran en conflicto con los valores de clave primaria del dispositivo. Esto parece ser el mismo que el error documentado aquí: http://code.djangoproject.com/ticket/7052

El problema es que la solución alternativa recomendada es volcar la aplicación contenttypes que ya estoy haciendo. ¿Lo que da? Si hace alguna diferencia, tengo algunos permisos de modelo personalizados como se documenta aquí: http://docs.djangoproject.com/en/dev/ref/models/options/#permissions

gerdemb
fuente

Respuestas:

148

manage.py dumpdata --naturalutilizará una representación más duradera de claves externas. En django se les llama "claves naturales". Por ejemplo:

  • Permission.codename se usa a favor de Permission.id
  • User.username se usa a favor de User.id

Leer más: sección de claves naturales en "serialización de objetos django"

Algunos otros argumentos útiles para dumpdata:

  • --indent=4 hágalo legible por humanos.
  • -e sessions excluir datos de sesión
  • -e admin excluir el historial de acciones de administración en el sitio de administración
  • -e contenttypes -e auth.Permissionexcluir objetos que se recrean automáticamente del esquema cada vez durante syncdb. Úselo solo junto con --naturalo de lo contrario podría terminar con números de identificación mal alineados.
Esquí
fuente
1
@skyjur ¿Por qué usar siempre -e contenttypes -e auth.permissioncon --natural? Lo intenté sin la --naturalopción y funcionó. Además, la documentación aquí dice que se debe usar esta opción si DUMPING auth.permission y contenttypes.
wlnirvana
6
@winirvana porque después de empezar desde cero y hacer syncdb, de nueva creación ContentTypey Permissionno está garantizado para conseguir mismo ID que tenían antes. Su volcado de datos contiene identificadores que pueden hacer referencia a diferentes objetos en otra base de datos donde cargará los datos. Podría funcionar para usted debido a una de estas razones: 1) sus datos no tenían ninguna referencia a estos objetos 2) se conservaron los identificadores originales de Permission / ContentTypes 3) su carga de datos tuvo éxito pero en realidad tiene datos corruptos debido a objetos refiriéndose a objetos incorrectos y aún no lo sabe
Esquí
12
La bandera --naturalahora está obsoleta a favor de --natural-foreign(y --natural-primary)
viernes
16
El comando final podría ser:manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4 > project_dump.json
Paolo
4
--naturalahora se ha eliminado por completo, no solo en desuso. Utilice --natural-foreigno en su --natural-primarylugar.
Code-Apprentice
35

Sí, esto es realmente irritante. Durante un tiempo lo solucioné haciendo un "restablecimiento de manage.py" en la aplicación contenttypes antes de cargar el dispositivo (para deshacerme de los datos de contenttypes generados automáticamente que diferían de la versión descargada). Eso funcionó, pero finalmente me cansé de las molestias y de los accesorios abandonados por completo a favor de los volcados SQL directos (por supuesto, luego pierdes la portabilidad de la base de datos).

actualizar : la mejor respuesta es usar la --naturalbandera para dumpdata, como se indica en una respuesta a continuación. Esa bandera aún no existía cuando escribí esta respuesta.

Carl Meyer
fuente
3
También me estaba encontrando con esto, restablecer la aplicación contenttypes también funcionó para mí. ¡Gracias por el consejo!
Beau
¿Cómo los restableciste? ¿En clase de caso de prueba? Dame un ejemplo, por favor
Oleg Tarasenko
4
No utilizo dispositivos para pruebas unitarias, generalmente creo datos de prueba usando el ORM en un método setup () porque es más fácil mantener la sincronización con las pruebas. Así que nunca tuve que hacer esto en una clase TestCase, aunque estoy seguro de que si hurgas en el código de la clase TestCase de Django, podrías descubrir cómo hacer que se restablezca después de la sincronización y antes de cargar el dispositivo en una subclase. Para mí fue simplemente "./manage.py reset contenttypes" en un script bash antes de "./manage.py loaddata my_fixture".
Carl Meyer
32

Intente omitir los tipos de contenido al crear el accesorio:

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

Me funcionó en una situación similar para las pruebas unitarias, ¡su conocimiento sobre los tipos de contenido realmente ayudó!

Evgeny
fuente
31

Las respuestas aquí son todas viejas ... A partir de 2017, la mejor respuesta es:

manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4
Hola Mundo
fuente
11

No estaba usando MySQL, sino que estaba importando algunos datos de un servidor en vivo a sqlite. Borrar los contenttypesdatos de la aplicación antes de realizar el proceso loaddatafuncionó:

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

Y entonces

python manage.py loaddata data.json
MadeOfAir
fuente
django.core.exceptions.ImproperlyConfigured: configuración solicitada INSTALLED_APPS, pero la configuración no está configurada. Debe definir la variable de entorno DJANGO_SETTINGS_MODULE o llamar a settings.configure () antes de acceder a la configuración.
Barney
Probablemente funcionaría mejor dentro del control de un comando de administración personalizado.
Barney
10

Resolví este problema en mis casos de prueba restableciendo la aplicación contenttypes de la prueba unitaria antes de cargar mi archivo de volcado. Carl sugirió esto ya usando el manage.pycomando y yo hago lo mismo solo usando el call_commandmétodo:

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

Mi full_test_data.jsondispositivo contiene el volcado de la aplicación contenttypes que corresponde al resto de los datos de prueba. Al restablecer la aplicación antes de cargarla, evita la clave duplicada IntegrityError.

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

Esto funciona para mi. Aquí estoy excluyendo todo lo que burbujea en los modelos reales.

  • Si ve cualquier otro modelo que no sean los modelos que creó, puede excluirlos de forma segura. Un inconveniente de este enfoque es que pierde tanto los datos de registro como los de autenticación.
Ojas Kale
fuente
6

Debe utilizar claves naturales para representar cualquier clave externa y relaciones de varios a varios. Además, podría ser una buena idea excluir la sessiontabla en la sessionsaplicación y la logentrytabla en la adminaplicación.

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

Según la documentación de Django , --naturalse ha desaprobado en la versión 1.7, por lo que la opción --natural-foreigndebería usarse en su lugar.

También puede omitir la clave principal en los datos serializados de este objeto, ya que se puede calcular durante la deserialización pasando la --natural-primarymarca.

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

cambiará

  "content_type": 123

a

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

Y el accesorio funciona por TestCaseahora

Daniil Mashkin
fuente
2

Django 2.2.5

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

Me ayudó

Igor Z
fuente
Planteará un problema cuando se carguen los datos, tal vez no coincida con el tipo de contenido en la nueva base de datos
yang zhou
1

Voy a dar otra posible respuesta que acabo de descubrir. Quizás ayude al OP, quizás ayude a alguien más.

Tengo una tabla de relaciones de muchos a muchos. Tiene una clave primaria y las dos claves foráneas para las otras tablas. Descubrí que si tengo una entrada en el dispositivo cuyas dos claves externas son iguales a otra entrada que ya está en la tabla con un pk diferente , fallará. Las tablas de relaciones M2M tienen un "conjunto único" para las dos claves externas.

Entonces, si se trata de una relación M2M que se está rompiendo, mire las claves externas que está agregando, mire su base de datos para ver si ese par de FK ya figura en una PK diferente.

orblivion
fuente
1

Es muy, muy molesto ... Esto me muerde cada vez.

Traté de volcar datos con --exclude contenttypes y --natural, siempre tengo problemas ...

Lo que funciona mejor para mí es simplemente hacer un truncate table django_content_type;después de syncdb y LUEGO cargar los datos.

Por supuesto, para la carga automática initial_data.json, estás en caída libre.

h3.
fuente
Para mí, truncar la tabla antes de loaddata solo causa diferentes errores. No tuve suerte con esta técnica.
shacker
1

A veces me había encontrado con un error similar. Resultó que estaba intentando cargar los dispositivos antes de crear las tablas necesarias. Así que lo hice:

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

Y funcionó como un encanto

James Wanderi
fuente
0

En mi caso, había descargado los datos de auth( ./manage.py dumpddata auth > fixtures/auth.json) para usar el dispositivo con fines de prueba.

El desarrollo continuó y eliminé la mayoría de los modelos que había definido models.pyy fue entonces cuando comencé a ver este molesto problema.

Mi solución fue volver a regenerar el accesorio auth.json. Este había eliminado muchas entradas auth.permissionrelacionadas con los modelos antiguos que tenía.

Pablo Castellano
fuente
0

Probé todos los métodos de arriba, nada funcionó para mí. Tengo que excluir el modelo de autenticación completo y funciona bien.

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