Подтвердить что ты не робот

Получение модели ContentType при миграции - Django 1.7

У меня есть перенос данных, который обновляет некоторые разрешения. Я знаю, что есть некоторые известные проблемы с разрешениями в миграциях, и я смог избежать некоторых проблем, создав разрешения в его миграции (а не используя ярлык кортежа в модели).

Миграция:

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

После некоторых проб и ошибок я смог выполнить эту работу с помощью manage.py migrate, но я получаю ошибки в тесте manage.py test.

__fake__.DoesNotExist: ContentType matching query does not exist.

Отладка бит обнаружила, что в этой точке миграции нет ContentType при запуске в тесте (непонятно почему). Следуя советам в этой post, я попробовал вручную обновлять типы контента вручную. Добавлено:

from django.contrib.contenttypes.management import update_contenttypes
update_contenttypes(app, models.get_models())

перед тем, как выбрать тип содержимого для модели Invitation. Получена следующая ошибка:

  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'

Должен существовать некоторый способ создания/обновления разрешений в миграциях данных тестовым способом.

Спасибо.

ИЗМЕНИТЬ

Наконец, это заставило работать, добавив

from django.contrib.contenttypes.management import update_all_contenttypes
update_all_contenttypes() 

как ни странно, этого недостаточно [/p >

update_contenttypes(apps.app_configs['contenttypes'])

Я хотел бы знать, почему все это необходимо

4b9b3361

Ответ 1

Аналогичная проблема возникает при записи миграции данных, которая охватывает несколько приложений. Оказывается, Django загружает только эти модели в реестр приложений, на которые влияет элемент состояния зависимостей миграции: https://code.djangoproject.com/ticket/24303 p >

Если бы в основном добавить запись к зависимостям миграции, которые я использую, это не связано напрямую, например. foreignKey для приложения, которое в настоящее время переносится.

Ответ 2

Ответ:

apps.get_model('contenttypes', 'ContentType') 

:) Понадобился сегодня сам.

Ответ 3

Так как я потратил 3-4 часа на это, я добавляю свое решение.

Проблема заключалась в том, что объекты ContentType и Permission не создавались, когда я запускал несколько миграций вместе. Поскольку я ссылался на этот тип контента и миграцию при следующей миграции, это вызывало проблемы.)

Однако они работают нормально, если я запускаю их один за другим, используя номер миграции. (на которые ссылались в будущих миграциях)

Чтобы решить эту проблему, я добавил дополнительную миграцию между ними для создания объектов ContentType и 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)
    ]

Ответ 4

update_contenttypes(apps.app_configs['contenttypes'])

обновит типы контента контента типов контента.

Я считаю, что вы захотите сделать это...

update_contenttypes(apps.app_configs['app_label']) 

где app_label - это метка приложения для приложения, в котором живет модель приглашения. Это будет обновлять ваши типы содержимого для одного приложения, чтобы оно было доступно для запроса в соответствии с вашим исходным кодом.

Ответ 5

Для Django 2.1 мне пришлось импортировать приложения из глобального реестра, потому что переданные приложения в миграцию были экземплярами django.db.migrations.state.AppConfigStub без заполненного атрибута models_module. И create_contenttypes проверяет этот атрибут.

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)

    ...