UNIQUE constraint failed: new__me_teacher.email

Я пытаюсь обновить миграции на своём проекте с расширенным пользователем models.py

class Teacher(AbstractUser):
    name = models.CharField(max_length=20, unique=False)
    surname = models.CharField(max_length=20)
    email = models.EmailField(max_length=255, unique=True)
    USERNAME_FIELD = 'email'
    user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True,
        on_delete=models.CASCADE)
    subject = models.ForeignKey(Subject, related_name='teacher_subject',
        null=True, on_delete=models.CASCADE)
    password = models.CharField(max_length=50)
    REQUIRED_FIELDS = ['name', 'surname', 'password']

Из-за чего может появиться такая ошибка? Изначально такая проблема была с Teacher.username, погуглил, что нужно добавить USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name', 'surname', 'password'] но лучше, как видно, не стало

Код ошибки:

Traceback (most recent call last):
  File "manage.py", line 21, in <module>
    main()
  File "manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "E:\Projects\mindless\django\core\management\__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "E:\Projects\mindless\django\core\management\__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "E:\Projects\mindless\django\core\management\base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "E:\Projects\mindless\django\core\management\base.py", line 364, in execute
    output = self.handle(*args, **options)
  File "E:\Projects\mindless\django\core\management\base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "E:\Projects\mindless\django\core\management\commands\migrate.py", line 234, in handle
    fake_initial=fake_initial,
  File "E:\Projects\mindless\django\db\migrations\executor.py", line 117, in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "E:\Projects\mindless\django\db\migrations\executor.py", line 147, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "E:\Projects\mindless\django\db\migrations\executor.py", line 245, in apply_migration
    state = migration.apply(state, schema_editor)
  File "E:\Projects\mindless\django\db\migrations\migration.py", line 124, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "E:\Projects\mindless\django\db\migrations\operations\fields.py", line 249, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File "E:\Projects\mindless\django\db\backends\sqlite3\schema.py", line 137, in alter_field
    super().alter_field(model, old_field, new_field, strict=strict)
  File "E:\Projects\mindless\django\db\backends\base\schema.py", line 535, in alter_field
    old_db_params, new_db_params, strict)
  File "E:\Projects\mindless\django\db\backends\sqlite3\schema.py", line 359, in _alter_field
    self._remake_table(model, alter_field=(old_field, new_field))
  File "E:\Projects\mindless\django\db\backends\sqlite3\schema.py", line 286, in _remake_table
    self.quote_name(model._meta.db_table),
  File "E:\Projects\mindless\django\db\backends\base\schema.py", line 137, in execute
    cursor.execute(sql, params)
  File "E:\Projects\mindless\django\db\backends\utils.py", line 99, in execute
    return super().execute(sql, params)
  File "E:\Projects\mindless\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "E:\Projects\mindless\django\db\backends\utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "E:\Projects\mindless\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "E:\Projects\mindless\django\db\utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "E:\Projects\mindless\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "E:\Projects\mindless\django\db\backends\sqlite3\base.py", line 383, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: UNIQUE constraint failed: new__me_teacher.email

при команде manage.py migrate

Последняя миграция:

# Generated by Django 2.2.4 on 2021-05-24 13:35

from django.db import migrations, models

def forwards_func(apps, schema_editor):
    User = apps.get_model("auth", "User")
    db_alias = schema_editor.connection.alias
    for x in Teachers.objects.filter(email='').count():
        x.email = f'fake_email_{x.pk}@fake_email.fake'

class Migration(migrations.Migration):

    dependencies = [
        ('me', '0007_auto_20210519_2106'),
    ]

    operations = [
        migrations.AlterField(
            model_name='teacher',
            name='email',
            field=models.EmailField(max_length=255, unique=True),
        ),
        migrations.RunPython(forwards_func),
    ]


Ответы (1 шт):

Автор решения: Za Ars

в миграции добавьте migrations.RunPython() где заполняйте незаполненные уникальные поля.


def forwards_func(apps, schema_editor):
    User = apps.get_model("auth", "User")
    db_alias = schema_editor.connection.alias
    for x in User.objects.using(db_alias).filter(email__isnull=True):
        x.email = f'fake_email_{x.pk}@fake_email.fake'

Если эти поля только появились в модели, и раньше их не было, то сначала нужно сделать это поле Nullable чтобы провести описанную выше операцию.

После заполнения, Nullable можно убрать



UPD: Корректный вариант (после общения в обсуждении)


from django.db import migrations, models

def forwards_func(apps, schema_editor):
    Teachers = apps.get_model("me", "Teachers")
    db_alias = schema_editor.connection.alias
    for x in Teachers.objects.filter(models.Q(email='')|models.Q(email__isnull='')):
        x.email = f'fake_email_{x.pk}@fake_email.fake'
        x.save()

class Migration(migrations.Migration):

    dependencies = [
        ('me', '0007_auto_20210519_2106'),
    ]

    operations = [ 
        migrations.RunPython(forwards_func), # <= Порядок имеет значение

        migrations.AlterField(
            model_name='teacher',
            name='email',
            field=models.EmailField(max_length=255, unique=True),
        ),
    ]


Если не сработает - раздели на 2 миграции. Первая заполняет, вторая - ставит unique

→ Ссылка