Почему я не могу назначить новое разрешение группе в той же миграции в Django

Я пытаюсь добавить новые миграции, следуя этому руководство Я добавил новое разрешение внутри Meta в поле permissions. Затем я создал миграцию и попытался изменить эту миграцию, чтобы обновить права группы на месте. Но получил DoesNotExist в эксплуатации RunPython.

from django.db import migrations


def assign_new_permission(apps, *args):
    Permission = apps.get_model('auth.Permission')
    Group = apps.get_model('auth.Group')
    # __fake__.DoesNotExist: Permission matching query does not exist.
    new_permission = Permission.objects.get(
        codename='my_new_permissoin_code')

    admins = Group.objects.get(name='Group name')
    admins.permissions.add(new_permission)


class Migration(migrations.Migration):
    dependencies = [
        ('my_app', '0066_some_migratoin'),
    ]

    operations = [
        migrations.AlterModelOptions(
            name='my_model',
            options = {'permissions': (('my_new_permissoin_code',
                                      'Permission name'),)},
        ),
        migrations.RunPython(assign_new_permission)
    ]
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 181
1

Ответы 1

Я думаю, что ваша проблема возникает из-за того, что разрешения фактически не создаются во время или после отдельной миграции, а запускаются сигналом после миграции, который отправляется после успешного завершения команды python manage.py migrate (см. Комментарии к принятому ответу здесь.)

Есть несколько способов обойти это:

  1. Разделите его на две отдельные миграции (создайте разрешения, а затем назначьте их) и запустите их двумя отдельными командами python manage.py migrate:

    python manage.py migrate my_app 0066_create_permissions
    python manage.py migrate my_app 0067_assign_permissions
    

    Это позволяет послать сигнал пост-миграции после запуска 0066 для создания разрешений.

  2. Разделите его на два шага внутри одной миграции, но вам придется вручную создать разрешения с помощью функции Python, а затем назначить их в другой. Чтобы учесть это, вам придется изменить свой operations. Одним из преимуществ этого является то, что при желании вы можете создать функцию или функции Python, чтобы отменить миграцию, что на самом деле невозможно для №3 или №4.

  3. Самостоятельно подайте сигнал после миграции во время миграции. Это хорошее решение для случаев, когда вам нужны разрешения от сторонних приложений (например, django-guardian, как в моем случае), чтобы вы могли применять их при миграции данных.

    from django.apps import apps as django_apps
    def guardian_post_migrate_signal(apps, schema_editor):
        guardian_config = django_apps.get_app_config('guardian')
        models.signals.post_migrate.send(
            sender=guardian_config,
            app_config=guardian_config,
            verbosity=2,
            interactive=False,
            using=schema_editor.connection.alias,
        )
    
  4. Это похоже на №3, но немного проще. Вероятно, есть тонкие способы, которыми лучше или хуже, но я не уверен, что это такое. Вы можете создать функцию, которая вызывает django.contrib.auth.management.create_permissions (кредит эта почта) и использовать ее непосредственно при миграции:

    from django.contrib.auth.management import create_permissions
    
    def create_perms(apps, schema_editor):
        for app_config in apps.get_app_configs():
            app_config.models_module = True
            create_permissions(app_config, apps=apps, verbosity=0)
            app_config.models_module = None
    

    Тогда ваш operations будет выглядеть так:

        operations = [
            migrations.AlterModelOptions(
                name='my_model',
                options = {'permissions': (('my_new_permission_code', 'Permission name'),)},
            ),
            migrations.RunPython(create_perms),
            migrations.RunPython(assign_perms)
        ]
    

В любом случае, я надеюсь, что это поможет. Извините за информационную перегрузку - у меня была та же проблема, что и у вас, в прошлом, и это отбросило меня на несколько дней.

Другие вопросы по теме