J'ai une migration de données qui met à jour certaines autorisations. Je sais qu'il y a des problèmes connus avec les autorisations dans les migrations et j'ai pu éviter certains problèmes en créant les autorisations dans la migration elle-même (plutôt qu'en utilisant le raccourci Tuple dans le modèle).
La migration:
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),
]
Après quelques essais et erreurs, j'ai pu faire ce travail en utilisant manage.py migrate
mais je reçois des erreurs dans le test manage.py test
.
__fake__.DoesNotExist: ContentType matching query does not exist.
Le débogage a découvert qu'il n'y avait pas de ContentType
à ce stade de la migration lors de l'exécution dans test (je ne sais pas pourquoi). En suivant les conseils de ce post j'ai essayé de mettre à jour les types de contenu manuellement dans la migration elle-même. Ajoutée :
from Django.contrib.contenttypes.management import update_contenttypes
update_contenttypes(app, models.get_models())
avant de récupérer le type de contenu pour le modèle Invitation
. Vous avez l'erreur suivante
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'
Il doit y avoir un moyen de créer/mettre à jour les autorisations dans les migrations de données de manière testable.
Merci.
[~ # ~] modifier [~ # ~]
Enfin, cela a fonctionné en ajoutant
from Django.contrib.contenttypes.management import update_all_contenttypes
update_all_contenttypes()
assez curieusement celui-ci n'était pas suffisant
update_contenttypes(apps.app_configs['contenttypes'])
J'aimerais savoir pourquoi tout cela est nécessaire
La réponse est:
apps.get_model('contenttypes', 'ContentType')
:) J'en avais besoin moi-même aujourd'hui.
Avoir un problème similaire lors de l'écriture d'une migration de données qui s'étend sur plusieurs applications. Il s'avère que Django charge uniquement les modèles dans le registre d'application qui sont affectés par ce que le membre "dépendances" de la migration déclare: https://code.djangoproject.com/ticket/243
J'ai dû ajouter une entrée aux dépendances de migration que j'utilise qui n'est pas directement liée par exemple une clé étrangère vers l'application en cours de migration.
Depuis, j'ai fini par y consacrer 3 à 4 heures, j'ajoute ma solution.
Le problème était ContentType et les objets d'autorisation n'étaient pas créés lorsque j'ai exécuté plusieurs migrations ensemble. Étant donné que je faisais référence à ce type de contenu et à la migration lors de la prochaine migration, cela posait problème.)
Cependant, ils fonctionnent bien si je les exécute un par un à l'aide du numéro de migration. (qui ont été référencés lors de futures migrations)
Pour le résoudre, j'ai ajouté une migration supplémentaire entre les deux pour créer des objets ContentType et Permission.
# -*- 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)
]
Pour Django 2.1 J'ai dû importer des applications du registre mondial car les applications passées dans la migration étaient des instances de Django.db.migrations.state.AppConfigStub
sans remplissage models_module
attribut. Et create_contenttypes
vérifie cet attribut.
from Django.apps.registry import Apps, apps as global_apps
from Django.contrib.contenttypes.management import create_contenttypes
from Django.db import migrations
def add_permision(apps: Apps, schema_editor):
gls_app_config = global_apps.get_app_config('my_app')
create_contenttypes(gls_app_config)
...
update_contenttypes(apps.app_configs['contenttypes'])
mettra à jour les types de contenu de l'application contenttypes.
Je pense que vous voudriez faire ça ...
update_contenttypes(apps.app_configs['app_label'])
où app_label est le libellé de l'application dans laquelle se trouve le modèle d'invitation. Cela mettra à jour les types de contenu de votre application afin qu'elle soit disponible pour interroger selon votre code d'origine.