Как сохранить дополнительные поля при регистрации, используя пользовательскую модель в DRF + django-rest-auth - PullRequest
0 голосов
/ 29 декабря 2018

Используя Django REST Framework (DRF), с django-rest-auth, я создал пользовательскую модель пользователя с одним дополнительным полем. Моя цель - использовать конечную точку регистрации django-rest-auth, чтобы зарегистрировать нового пользователя в одном запросе и, таким образом, отправить все данные для создания нового пользователя, включая данные для дополнительного поля.

Я использую AbstractUser, поскольку он рекомендуется для начинающих, где более продвинутые разработчики могут использовать AbstractBaseUser.Вот почему следующие ответы SO выглядят слишком сложными для того, чего я хочу достичь: ссылка здесь .

Я знаю, что этот вопрос задавался несколько раз, но ответыне совсем то, что я ищу.Для новичка, как я, это сложная вещь.

Итак, мой вопрос, может ли кто-нибудь объяснить, как добиться того, чего я хочу?

Я использую:

Django              2.1.4
django-allauth      0.38.0
django-rest-auth    0.9.3
djangorestframework 3.9.0

Вот код, который у меня есть до этого момента:

Использовал этот урок , чтобы добраться до этого кода

settings.py:

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!gxred^*penrx*qlb=@p)p(vb!&6t78z4n!poz=zj+a0_9#sw1'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'rest_framework',
    'rest_framework.authtoken',

    'rest_auth',

    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'rest_auth.registration',

    'users',
]

SITE_ID = 1

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'DRF_custom_user.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'DRF_custom_user.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_URL = '/static/'

AUTH_USER_MODEL = 'users.CustomUser'

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

users.models.py:

from django.contrib.auth.models import AbstractUser
from django.db import models


class CustomUser(AbstractUser):
    preferred_locale = models.CharField(blank=True, null=True, max_length=2)

users.admin.py:

from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin

from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser

class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser
    list_display = ['email', 'preferred_locale']

admin.site.register(CustomUser, CustomUserAdmin)

users.forms.py:

from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser


class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm):
        model = CustomUser
        fields = ('email', )


class CustomUserChangeForm(UserChangeForm):

    class Meta:
        model = CustomUser
        fields = UserChangeForm.Meta.fields

Ответы [ 2 ]

0 голосов
/ 05 января 2019

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

То, что я написал ниже, я написал с учетом потенциальной записи в блоге.

Я предполагаю, что вы знаете, как настроить проект DRF и установить вышеупомянутые пакеты.В документации django-rest-auth ясно, как установить этот пакет (https://django -rest-auth.readthedocs.io / en / latest / index.html ), также обязательно следуйте инструкциямустановить часть django-rest-auth для регистрации пользователей.

Создать новое приложение 'users'

Это приложение будет содержать мой пользовательский код для реализации пользовательскихпользовательская модель.Я также устанавливаю его в основной файл настроек Django:

settings.py:

INSTALLED_APPS = [
    ...
    'users',
]

Создайте свою пользовательскую модель

Обратите внимание, что ятолько что добавили одно настраиваемое поле, но вы можете добавить любые поля, которые вам нужны.

users.models.py:

from django.contrib.auth.models import AbstractUser
from django.db import models


class CustomUser(AbstractUser):
    preferred_locale = models.CharField(max_length=2, blank=True, null=True)

Скажите django использовать модель CustomUser

settings.py:

…
AUTH_USER_MODEL = 'users.CustomUser'

Регистрация пользовательской модели пользователя в Django admin

users.admin.py:

from django.contrib import admin

from .models import CustomUser


admin.site.register(CustomUser)

Выполните миграции и запустите их

Впервые я делаю это для этого проекта.

В командной строке:

python manage.py makemigrations users
python manage.py migrate

Регистрация новых пользователей с дополнительными полями

Если вы запустите сервер разработки Django сейчас, вы увидите в администраторе, что вы можете видеть пользовательскую модель пользователя с дополнительными полями.

Но когда вы переходите к 'http://127.0.0.1:8000/rest-auth/registration/’, вы еще не видите дополнительных полей.

В процессе регистрации пользователя используются два важных класса,а именно:

  • сериализатор 'rest_auth.registration.RegisterSerializer'
  • адаптер 'allauth.account.adapter.DefaultAccountAdapter'

Мы сделаемпользовательская версия обоих, наследующая все функциональные возможности родительского класса.

Создание пользовательского RegisterSerializer

Создайте новый файл 'serializers.py' вusers app / folder.

users.serializers.py:

from rest_framework import serializers

from allauth.account.adapter import get_adapter
from allauth.account.utils import setup_user_email

from rest_auth.registration.serializers import RegisterSerializer


class CustomRegisterSerializer(RegisterSerializer):
    preferred_locale = serializers.CharField(
        required=False,
        max_length=2,
    )

    def get_cleaned_data(self):
        data_dict = super().get_cleaned_data()
        data_dict['preferred_locale'] = self.validated_data.get('preferred_locale', '')
        return data_dict

Здесь я создаю новое поле для каждого дополнительного поля в пользовательской модели пользователя.Так что в моем случае добавлено следующее:

preferred_locale = serializers.CharField(
        required=False,
        max_length=2,
    )

Кроме того, метод get_cleaned_data должен возвращать dict, который содержит все данные для полей, которые вы хотите сохранить при регистрации нового пользователя.

Вот как выглядит оригинальный метод (по умолчанию RegisterSerializer):

def get_cleaned_data(self):
    return {
        'username': self.validated_data.get('username', ''),
        'password1': self.validated_data.get('password1', ''),
        'email': self.validated_data.get('email', '')
    }

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

В моем случае, требуется только добавить данные для поля 'selected_locale', это результирующий метод:

def get_cleaned_data(self):
    data_dict = super().get_cleaned_data()
    data_dict['preferred_locale'] = self.validated_data.get('preferred_locale', '')
    return data_dict

Скажите django использовать этот новый сериализатор

settings.py:

REST_AUTH_REGISTER_SERIALIZERS = {
    'REGISTER_SERIALIZER': 'users.serializers.CustomRegisterSerializer',
}

Предотвращение ошибок

Если вы попытаетесь зарегистрировать нового пользователя, вы можете получить следующую ошибку в консоли, на которой работает сервер разработки: ConnectionRefusedError: [Errno 111] Соединение отклонено

Хотя пользовательЭта ошибка по-прежнему может быть исправлена ​​путем добавления в файл settings.py следующей строки:

settings.py:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Другая ошибка, которая возникает при удалении пользователя,:

django.db.utils.OperationalError: no such table: allauth_socialaccount

Чтобы решить эту проблему, добавьте это в ваши settings.py:

settings.py:

INSTALLED_APPS = [
    ...
    'allauth.socialaccount',  
]

После этого вы должны применить миграции до того, какможно продолжить:

python manage.py migrate

Созданиепользовательский AccountAdapter

После выполнения описанных выше действий, go '1126 *http://127.0.0.1:8000/rest-auth/registration/’ покажет вам дополнительные поля.Но когда вы регистрируете нового пользователя и отправляете данные для дополнительных полей, данные дополнительного поля не сохраняются.

Последнее, что нам нужно сделать, чтобы решить эту проблему, - это создать собственный AccountAdapter

В нашем пользовательском приложении / папке создайте новый файл с именем 'adapter.py':

users.adapter.py:

from allauth.account.adapter import DefaultAccountAdapter


class CustomAccountAdapter(DefaultAccountAdapter):

    def save_user(self, request, user, form, commit=False):
        user = super().save_user(request, user, form, commit)
        data = form.cleaned_data
        user.preferred_locale = data.get('preferred_locale')
        user.save()
        return user

Здесь, если вы выполнили вышеуказанные шагиправильно, вы можете получить доступ к данным дополнительных добавленных полей в словаре form.cleaned_data.Это словарь, который возвращается методом get_cleaned_data из нашего пользовательского RegisterSerializer.

В приведенном выше методе save_user мы можем затем использовать эти данные и сохранить их в соответствующих полях, например:

user.preferred_locale = data.get('preferred_locale')

Скажите Django использовать эти новые адаптеры

settings.py:

ACCOUNT_ADAPTER = 'users.adapter.CustomAccountAdapter'

Теперь вы можете зарегистрировать своего пользователя, используя конечную точку регистрации django-rest-auth '/ rest-auth / registration / 'и отправьте данные для дополнительных полей, которые вы добавили.Все это будет сохранено в одном запросе.

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

0 голосов
/ 29 декабря 2018

Давайте разберем ваш вопрос.Обратите внимание, что я объясняю вам основы Django REST Framework.

Переопределение модели пользователя

  • [x] Шаг 1: Вы переопределяете модель User: Вы сделали это.Альтернатива?Да.Создайте модель, у которой OneToOneForeignKey указывает на User модель.
  • [x] Шаг 2. Используйте это CustomUserModel.Для этого вам необходимо установить AUTH_USER_MODEL в settings.py Ссылка на официальную документацию Вы сделали это.
  • [] Шаг 3: Создать UserManager для обработки регистрации пользователя иДополнительная информация.Вы этого не сделали.

Регистрация в API

  • [] Создайте serializer, в котором четко указаны все обязательные поля, которые вы ожидаете от концапользователь.Вы даже можете использовать serializer.ModelSerializer, если нет пользовательских полей.
  • [] Обрабатывать явные проверки в самом serializer.Используйте def validate(self, attrs), если требуется.Вот ссылка официальный документ .
  • [] Наконец, создайте представление и используйте APIView, так как вы захотите зарегистрировать пользователя, используя UserManager, который вы создали выше.

Я также могу сослаться на приложение, которое я создал сам.Вот ссылка: DRF-USER .Я настроил модель User до некоторой степени и следовал тому же процессу.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...