Избегайте создания поля имени пользователя в пользовательской модели для django allauth - PullRequest
0 голосов
/ 29 мая 2020

Я использую настраиваемую модель пользователя с allauth, и мне нужно, чтобы поле имени пользователя было опущено. Я уже видел документы и целую кучу ответов stackoverflow об использовании ACCOUNT_USER_MODEL_USERNAME_FIELD = None, но все это по-прежнему приводит к тому, что моя база данных имеет поле имени пользователя.

Теперь, поскольку в базе данных все еще есть поле username с уникальным ограничением, установленным на и , allauth не будет помещать имя пользователя в поле с вышеупомянутым параметром, установленным на None, это заставляет меня столкнуться с IntegrityError после самого первого создания пользователя. Я знаю, что могу решить эту проблему, просто установив для вышеупомянутого параметра значение 'username', но мне любопытно, как мне просто не указать имя пользователя, потому что я никогда его не использую.

Моя модель:

class CustomUser(AbstractUser):
    # Custom user model for django-allauth
    first_name = None
    last_name = None

    def delete(self):
        # Custom delete - make sure user storage is also purged
        # Purge the user storage
        purge_userstore(self.email)
        # Call the original delete method to take care of everything else
        super(CustomUser, self).delete()

На самом деле он ничего не делает, кроме переопределения функции delete. Это переопределение не имеет отношения к этому топи c, но я включил его только для полноты картины. Он также устанавливает first_name и last_name на None, что отлично работает и удаляет эти поля из базы данных, как ожидалось. Я пробовал установить user на None, но это ничего не дает. Я также пробовал установить username на None, но это вызовет ошибку FieldNotFound с ACCOUNT_USER_MODEL_USERNAME_FIELD = None

Мои настройки (соответствующий бит):

AUTHENTICATION_BACKENDS = (
    "django.contrib.auth.backends.ModelBackend",
    "allauth.account.auth_backends.AuthenticationBackend",
)
AUTH_USER_MODEL = 'custom_account.CustomUser'
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_AUTHENTICATION_METHOD = 'email'

My файл миграции:

migrations.CreateModel(
            name='CustomUser',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('password', models.CharField(max_length=128, verbose_name='password')),
                ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
                ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
                ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
                ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
                ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
                ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
                ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
                ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
                ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
            ],
....

Это поколение миграции до бесконечности сбивает меня с толку. Почему поле username все еще там? Почему это единственное уникальное ограничение, хотя я четко установил ACCOUNT_UNIQUE_EMAIL = True?

Примечание : этот файл миграции создается с чистого листа, это первый и только файл миграции, созданный из представленного мною кода.

Сначала я подумал, что мои настройки просто не читаются. Но я проверил django.conf.settings и allauth.account.app_settings (в оболочке) на предмет этих изменений, и все они были обновлены. Что здесь происходит?

Примечание : Среди множества вопросов о переполнении стека, которые я искал, этот вопрос, в частности, кажется, прекрасно объясняет мою проблему. С одной небольшой проблемой, в ответе самого создателя allauth предлагалось использовать ACCOUNT_USER_MODEL_USERNAME_FIELD = "username", поскольку рассматриваемая модель «явно использует поле username». Но ответ не объясняет, что делать, если вы вообще не хотите использовать поле username.

1 Ответ

0 голосов
/ 29 мая 2020

Похоже, единственный способ избавиться от поля username - это переопределить поле имени пользователя AbstractUser и / или использовать полностью настраиваемую модель с нуля. Переопределение мыслей AbstractBaseUser тоже должно работать, хотя AbstractBaseUser обеспечивает меньшую функциональность.

class CustomUser(AbstractUser):
    # Custom user model for django-allauth
    # Remove unnecessary fields
    username = None
    first_name = None
    last_name = None
    # Set the email field to unique
    email = models.EmailField(_('email address'), unique=True)
    # Get rid of all references to the username field
    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

Эта модель удалит поле username и сделает поле email уникальным, а также изменит все ссылки на USERNAME_FIELD на 'email'. Обратите внимание, что REQUIRED_FIELDS должно быть пустым, поскольку USERNAME_FIELD там не может быть. При использовании allauth это не проблема, требования к электронной почте и паролю в любом случае управляются allauth.

Настройки, которые я упомянул в вопросе, должны остаться прежними, в частности -

ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True
...