only - django runpython
Obtener el modelo ContentType en migraciĆ³n-Django 1.7 (4)
Tengo una migración de datos que actualiza algunos permisos. Sé que hay algunos problemas conocidos con los permisos en las migraciones y pude evitar algunos problemas al crear los permisos en la migración (en lugar de utilizar el acceso directo tupla en el modelo).
La migración:
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
def create_feature_groups(apps, schema_editor):
app = models.get_app(''myauth'')
Group = apps.get_model("auth", "Group")
pro = Group.objects.create(name=''pro'')
Permission = apps.get_model("auth", "Permission")
ContentType = apps.get_model("contenttypes", "ContentType")
invitation_contenttype = ContentType.objects.get(name=''Invitation'')
send_invitation = Permission.objects.create(
codename=''send_invitation'',
name=''Can send Invitation'',
content_type=invitation_contenttype)
pro.permissions.add(receive_invitation)
class Migration(migrations.Migration):
dependencies = [
(''myauth'', ''0002_initial_data''),
]
operations = [
migrations.RunPython(create_feature_groups),
]
Después de algunas pruebas y errores, pude hacer que esto funcionara usando manage.py migrate
pero recibo errores en la prueba manage.py test
.
__fake__.DoesNotExist: ContentType matching query does not exist.
Depurando un poco descubrió que no hay ContentType
en este punto de la migración cuando se ejecuta en prueba (no estoy seguro de por qué). Siguiendo los consejos de esta post intenté actualizar manualmente los tipos de contenido en la migración. Adicional :
from django.contrib.contenttypes.management import update_contenttypes
update_contenttypes(app, models.get_models())
antes de ir a buscar el tipo de contenido para el modelo de Invitation
. Obtuvo el siguiente error
File "C:/Python27/lib/site-packages/django-1.7-py2.7.egg/django/contrib/contenttypes/management.py", line 14, in update_contenttypes
if not app_config.models_module:
AttributeError: ''module'' object has no attribute ''models_module''
Debe haber alguna forma de crear / actualizar permisos en migraciones de datos de forma comprobable.
Gracias.
EDITAR
Finalmente lo hizo funcionar al agregar
from django.contrib.contenttypes.management import update_all_contenttypes
update_all_contenttypes()
Curiosamente, este no era suficiente
update_contenttypes(apps.app_configs[''contenttypes''])
Me encantaría saber por qué todo esto es necesario
Desde que terminé gastando 3-4 horas en esto, estoy agregando mi solución.
El problema era ContentType y los objetos de permiso no se creaban cuando ejecutaba varias migraciones juntas. Dado que estaba haciendo referencia a este tipo de contenido y a la migración en la próxima migración, esto causaba problemas).
Sin embargo, funcionan bien si los ejecuto uno por uno usando el número de migración. (que fueron referenciados en futuras migraciones)
Para resolverlo, agregué una migración adicional para crear ContentType y objetos de permiso.
# -*- coding: utf-8 -*-
# Generated by Django 1.10.6 on 2017-03-11 05:59
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations
def update_all_contenttypes(**kwargs):
from django.apps import apps
from django.contrib.contenttypes.management import update_contenttypes
for app_config in apps.get_app_configs():
update_contenttypes(app_config, **kwargs)
def create_all_permissions(**kwargs):
from django.contrib.auth.management import create_permissions
from django.apps import apps
for app_config in apps.get_app_configs():
create_permissions(app_config, **kwargs)
def forward(apps, schema_editor):
update_all_contenttypes()
create_all_permissions()
def backward(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
(''contenttypes'', ''0002_remove_content_type_name''),
(''MY_APP'', ''0123_LAST_MIGRATION''),
]
operations = [
migrations.RunPython(forward, backward)
]
La respuesta es:
apps.get_model (''contenttypes'', ''ContentType'') :) Lo necesitaba yo mismo hoy.
Tener un problema similar al escribir una migración de datos que abarca varias aplicaciones. Resulta que Django solo carga esos modelos en el registro de la aplicación que se ven afectados por lo que dice el miembro de "dependencias" de la migración: https://code.djangoproject.com/ticket/24303
Tuve que, básicamente, agregar una entrada a las dependencias de migración que uso que no está directamente relacionada, por ejemplo, una ForeignKey con la aplicación que se está migrando actualmente.
update_contenttypes(apps.app_configs[''contenttypes''])
actualizará los tipos de contenido de la aplicación de tipos de contenido.
Creo que querrías hacer esto ...
update_contenttypes(apps.app_configs[''app_label''])
donde app_label es la etiqueta de la aplicación para la que vive el modelo de invitación. Esto actualizará los tipos de contenido de su aplicación individual para que esté disponible para consultas según su código original.