Пользовательская миграция данных django создание записей allauth.account EmailAddress модель возвращает ошибку - django.db.migrations.exceptions.NodeNotFoundError:

Я обновляю проект django, который был создан с помощью стандартного django auth. Проверка электронной почты была реализована с помощью пакета django.contrib.auth.tokens. Это работало так: флаг 'is_active' пользователя по умолчанию django, который сам расширен пользовательским пользователем, изначально устанавливается в False и меняется на True после того, как пользователь верифицирует электронную почту.

Теперь я обновил проект для использования django-allauth, добился того, что все остальное работает просто отлично (в разработке), за исключением проверки электронной почты. Поскольку django-allauth расширяет модель User моделью EmailAddress и проверяет флаг 'verified' в этой модели, чтобы определить, был ли email проверен/подтвержден, я решил написать пользовательскую миграцию данных, которая создает записи в таблице EmailAddress и устанавливает verified = True, если user.is_active = True. Однако я получаю ошибку, описанную ниже:

django.db.migrations.exceptions.NodeNotFoundError: Migration accounts.0003_create_allauth_email_records_for_existing_users dependencies reference non-xistent parent node ('allauth.account', '0002_email_max_length')

accounts/migrations/0003_create_allauth_email_records_for_existing_users.py

# Generated by Django 3.2.11 on 2022-12-09 10:56

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0002_delete_profile'),
        ('allauth.account', '0002_email_max_length')
    ]

    def create_allauth_email_records_for_existing_users(apps, schema_editor):

        UserModel = apps.get_model("accounts", "User")
        EmailMoldel = apps.get_model("allauth.account", "EmailAddress")

        for user in UserModel.objects.all():
            email_record = EmailMoldel.objects.filter(email=user.email).first()
            
            if email_record == None:

                if user.is_active:
                    email_verified = True
                else:
                    email_verified = False

                new_email = EmailMoldel.objects.create(
                    user = user,
                    email = user.email,
                    verified = email_verified,
                    )
    
    def reverse_func(apps, schema_editor):
        UserModel = apps.get_model("accounts", "User")
        EmailMoldel = apps.get_model("allauth.account", "EmailAddress")

        for email in EmailMoldel.objects.all():
            if not email.primary:
                email.delete()

    operations = [
        migrations.RunPython(
           create_allauth_email_records_for_existing_users, reverse_code= reverse_func
        )
    ]

accounts/models.py:

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import gettext_lazy as _

class User(AbstractUser):
    email = models.EmailField(_('email address'), unique=True)

Файл настроек: project/settings/base.py

Вот ошибка и трассировка стека

Traceback (most recent call last):
  File "C:\Users\USER\[**]\manage.py", line 22, in <module>
    main()
  File "C:\Users\USER\[**]\manage.py", line 18, in main    execute_from_command_line(sys.argv)
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\core\management\__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\core\management\__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\core\management\base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\core\management\base.py", line 398, in execute
    output = self.handle(*args, **options)
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\core\management\base.py", line 89, in wrapped
    res = handle_func(*args, **kwargs)
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\core\management\commands\migrate.py", line 92, in handle
    executor = MigrationExecutor(connection, self.migration_progress_callback)
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\db\migrations\executor.py", line 18, in __init__
    self.loader = MigrationLoader(self.connection)
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\db\migrations\loader.py", line 53, in __init__
    self.build_graph()
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\db\migrations\loader.py", line 259, in build_graph
    self.graph.validate_consistency()
  File "C:\Users\[**]\myEnv\lib\site-packages\django\db\migrations\graph.py", line 195, in validate_consistency
    [n.raise_error() for n in self.node_map.values() if isinstance(n, DummyNode)]
  File "C:\Users[**]\myEnv\lib\site-packages\django\db\migrations\graph.py", line 195, in <listcomp>
    [n.raise_error() for n in self.node_map.values() if isinstance(n, DummyNode)]
  File "C:\Users\USER\[**]\myEnv\lib\site-packages\django\db\migrations\graph.py", line 58, in raise_error
    raise NodeNotFoundError(self.error_message, self.key, origin=self.origin)
django.db.migrations.exceptions.NodeNotFoundError: Migration accounts.0003_create_allauth_email_records_for_existing_users dependencies reference nonexistent parent node ('allauth.account', 
'0002_email_max_length')

Проблема возникает из-за этого фрагмента в файле миграции:

dependencies = [
        ('accounts', '0002_delete_profile'),
        ('allauth.account', '0002_email_max_length')
    ]

Очевидно, что 'allauth.account' не является допустимым родительским узлом. Однако удаление его из зависимостей приводит к ошибке, описанной здесь: https://docs.djangoproject.com/en/4.1/howto/writing-migrations/#migrating-data-between-third-party-apps.

Другие темы, которые я нашел здесь, предлагают удалить миграцию или сбросить db, что не является приемлемым вариантом для меня. Как мне написать пользовательскую миграцию данных, которая сможет найти приложение 'allauth.account'?

Заранее спасибо!!!

установлен ли пакет в вашей среде?

pip install django-allauth

Так что я разобрался с этим, и это оказалось проще, чем я думал.

Очевидно, мне просто нужно было использовать "account" вместо "allauth.account" в файле миграций. Это не всегда может показаться очевидным (по крайней мере, для меня это было не так), потому что если посмотреть на библиотеку django-allauth, то account очень похож на вложенное приложение. Также, использование "allauth.account" работает в settings.INSTALLED_APPS.

New accounts/migrations/0003_create_allauth_email_records_for_existing_users.py:

# Generated by Django 3.2.11 on 2022-12-09 10:56

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0002_delete_profile'),
        ('account', '0002_email_max_length') # ***changed here
    ]

    def create_allauth_email_records_for_existing_users(apps, schema_editor):

        UserModel = apps.get_model("accounts", "User")
        EmailMoldel = apps.get_model("account", "EmailAddress") # ***changed here

        for user in UserModel.objects.all():
            email_record = EmailMoldel.objects.filter(email=user.email).first()
            
            if email_record == None:

                if user.is_active:
                    email_verified = True
                else:
                    email_verified = False

                new_email = EmailMoldel.objects.create(
                    user = user,
                    email = user.email,
                    verified = email_verified,
                    )
    
    def reverse_func(apps, schema_editor):
        UserModel = apps.get_model("accounts", "User")
        EmailMoldel = apps.get_model("account", "EmailAddress") # ***changed here

        for email in EmailMoldel.objects.all():
            if not email.primary:
                email.delete()

    operations = [
        migrations.RunPython(
           create_allauth_email_records_for_existing_users, reverse_code= reverse_func
        )
    ]

Вернуться на верх