Миграция Django завершается с ошибкой __fake__.DoesNotExist: запрос на сопоставление разрешений не существует.

В проекте Django 1.8 у меня отлично работает миграция, когда у него был следующий код:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations
from django.conf import settings


def update_site_forward(apps, schema_editor):
    """Add group osmaxx."""
    Group = apps.get_model("auth", "Group")
    Group.objects.create(name=settings.OSMAXX_FRONTEND_USER_GROUP)


def update_site_backward(apps, schema_editor):
    """Revert add group osmaxx."""
    Group = apps.get_model("auth", "Group")
    Group.objects.get(name=settings.OSMAXX_FRONTEND_USER_GROUP).delete()


class Migration(migrations.Migration):

    dependencies = [
        ('auth', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(update_site_forward, update_site_backward),
    ]

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

def update_site_forward(apps, schema_editor):
    """Add group osmaxx."""
    Group = apps.get_model("auth", "Group")
    Permission = apps.get_model("auth", "Permission")
    ContentType = apps.get_model("contenttypes", "ContentType")
    ExtractionOrder = apps.get_model("excerptexport", "ExtractionOrder")
    group = Group.objects.create(name=settings.OSMAXX_FRONTEND_USER_GROUP)
    content_type = ContentType.objects.get_for_model(ExtractionOrder)
    permission = Permission.objects.get(codename='add_extractionorder',
                                        content_type=content_type) # line 16
    group.permissions.add(permission)

и Migration.dependencies в:

    dependencies = [
        ('contenttypes', '0002_remove_content_type_name'),
        ('excerptexport', '0001_initial'),
        ('auth', '0001_initial'),
    ]

При применении миграции (после первого ее возврата) (python3 manage.py migrate auth 0001 && python3 managy.py migrate) сработало, миграция только что созданной базы данных PostgreSQL с помощью этой и всех других миграций (python3 manage.py migrate) не удалась:

Operations to perform:
  Synchronize unmigrated apps: debug_toolbar, django_extensions, messages, humanize, social_auth, kombu_transport_django, staticfiles
  Apply all migrations: excerptexport, admin, sites, contenttypes, sessions, default, stored_messages, auth
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
  Installing custom SQL...
Running migrations:
  Rendering model states... DONE
  Applying auth.0002_add_default_usergroup_osmaxx...Traceback (most recent call last):
  File "manage.py", line 17, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/base.py", line 393, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/commands/migrate.py", line 221, in handle
    executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
  File "/usr/local/lib/python3.4/dist-packages/django/db/migrations/executor.py", line 110, in migrate
    self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
  File "/usr/local/lib/python3.4/dist-packages/django/db/migrations/executor.py", line 148, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/usr/local/lib/python3.4/dist-packages/django/db/migrations/migration.py", line 115, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/usr/local/lib/python3.4/dist-packages/django/db/migrations/operations/special.py", line 183, in database_forwards
    self.code(from_state.apps, schema_editor)
  File "/home/osmaxx/source/osmaxx/contrib/auth/migrations/0002_add_default_usergroup_osmaxx.py", line 16, in update_site_forward
    permission = Permission.objects.get(codename='add_extractionorder', content_type=content_type)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/manager.py", line 127, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/query.py", line 334, in get
    self.model._meta.object_name
__fake__.DoesNotExist: Permission matching query does not exist.

Что я делаю не так?


person das-g    schedule 21.07.2015    source источник
comment
Примечание. Полный код проекта (без указанного изменения) доступен на GitHub. . Упомянутая миграция: py/osmaxx/contrib/auth/migrations/0002_add_default_usergroup_osmaxx.py Но, пожалуйста, прокомментируйте, если что-то там, но не упомянутое в вопросе, имеет отношение к ответу на вопрос, чтобы я мог включить это в вопрос.   -  person das-g    schedule 21.07.2015


Ответы (1)


Разрешения по умолчанию создаются в обработчике сигналов post_migrate после выполнения миграции. Это не будет проблемой, если ваш обновленный код запустится как часть второго manage.py migrate запуска, но это проблема в наборе тестов и любом новом развертывании.

Простое исправление - изменить эту строку:

permission = Permission.objects.get(codename='add_extractionorder',
                                    content_type=content_type) # line 16

к этому:

permission, created = Permission.objects.get_or_create(codename='add_extractionorder',
                                              content_type=content_type)

Обработчик сигналов, создающий разрешения по умолчанию, никогда не создаст дубликаты разрешений, поэтому безопасно создавать их, если они еще не существуют.

person knbk    schedule 21.07.2015
comment
Итак, разрешения создаются после всех миграций, а не после каждой отдельной миграции? - person das-g; 21.07.2015
comment
Сигнал post_migrate срабатывает каждый раз, когда завершается команда manage.py migrate, так что да, если вы применяете все миграции одновременно, он срабатывает после выполнения всех миграций. - person knbk; 21.07.2015
comment
В этом ответе есть обходной путь: stackoverflow.com/questions/31735042/ - person Apollo Data; 31.12.2016
comment
также можно перейти к миграции непосредственно перед ней. затем продолжите миграцию как обычно. это решило это для меня. - person Ajurna; 21.08.2017
comment
Спас мой день, спасибо! Странно, но в документации по миграции это не упоминается. - person Eugene Pakhomov; 05.08.2018