Rik*_*eek 3 django django-rest-framework django-allauth django-rest-auth
使用带有django-rest-auth的Django REST Framework(DRF),我创建了一个带有一个额外字段的自定义用户模型。我的目标是使用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
Run Code Online (Sandbox Code Playgroud)
这是到目前为止的代码:
使用本教程来获得此代码
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'
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
Rik*_*eek 11
我自己去寻找答案。花一些时间来研究源代码。我意识到此解决方案可能会缺少对添加到自定义用户模型中的额外字段的实际验证,但是稍后我会进行研究。
我在下面写的内容是在考虑潜在博客帖子的情况下写的。
我将假设您知道如何设置DRF项目并安装上述软件包。django-rest-auth文档明确说明了如何安装该软件包(https://django-rest-auth.readthedocs.io/en/latest/index.html),请确保还遵循以下步骤来安装该部件django-rest-auth用于用户注册。
创建一个新的应用程序“用户”
该应用程序将保存我的用于实现自定义用户模型的自定义代码。我还将其安装在Django主要设置文件中:
settings.py:
INSTALLED_APPS = [
...
'users',
]
Run Code Online (Sandbox Code Playgroud)
创建我的自定义用户模型
请注意,我只是添加了一个自定义字段,但是您可以添加所需的任何字段。
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)
Run Code Online (Sandbox Code Playgroud)
告诉Django使用CustomUser模型
settings.py:
…
AUTH_USER_MODEL = 'users.CustomUser'
Run Code Online (Sandbox Code Playgroud)
在Django管理员处注册自定义用户模型
users.admin.py:
from django.contrib import admin
from .models import CustomUser
admin.site.register(CustomUser)
Run Code Online (Sandbox Code Playgroud)
进行迁移并运行它们
这是我第一次为此项目做。
在命令行中:
python manage.py makemigrations users
python manage.py migrate
Run Code Online (Sandbox Code Playgroud)
使用其他字段注册新用户
如果现在启动Django开发服务器,您将在admin中看到可以看到自定义用户模型以及其他字段。
但是,当您转到“ http://127.0.0.1:8000/rest-auth/registration/ ”时,您还没有看到额外的字段。
在用户注册过程中,使用了两个重要的类,即:
我们将为这两者创建一个自定义版本,以继承其父类的所有功能。
创建一个自定义的RegisterSerializer
在用户应用/文件夹中创建一个新文件“ serializers.py”。
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
Run Code Online (Sandbox Code Playgroud)
在这里,我为自定义用户模型上的每个其他字段创建一个新字段。因此,在我的情况下,添加了以下内容:
preferred_locale = serializers.CharField(
required=False,
max_length=2,
)
Run Code Online (Sandbox Code Playgroud)
另外,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', '')
}
Run Code Online (Sandbox Code Playgroud)
如您所见,它返回一个字典,其中包含新用户的所有数据。您想为已添加到自定义用户模型中的每个额外字段向此字典添加keyval条目。
就我而言,只需为字段“ preferred_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
Run Code Online (Sandbox Code Playgroud)
告诉Django使用这个新的序列化器
settings.py:
REST_AUTH_REGISTER_SERIALIZERS = {
'REGISTER_SERIALIZER': 'users.serializers.CustomRegisterSerializer',
}
Run Code Online (Sandbox Code Playgroud)
预防错误
如果尝试注册新用户,则在运行开发服务器的控制台中可能会收到以下错误:ConnectionRefusedError:[Errno 111]连接被拒绝
尽管仍在创建用户,但是您可以通过将以下行添加到settings.py文件中来解决此错误:
settings.py:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Run Code Online (Sandbox Code Playgroud)
删除用户时将发生的另一个错误是:
django.db.utils.OperationalError: no such table: allauth_socialaccount
Run Code Online (Sandbox Code Playgroud)
要解决此问题,请将其添加到您的settings.py中:
settings.py:
INSTALLED_APPS = [
...
'allauth.socialaccount',
]
Run Code Online (Sandbox Code Playgroud)
之后,您应该先应用迁移,然后才能继续:
python manage.py migrate
Run Code Online (Sandbox Code Playgroud)
创建一个自定义AccountAdapter
完成上述步骤后,转到“ 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
Run Code Online (Sandbox Code Playgroud)
在这里,如果您正确地执行了上述步骤,则可以访问form.cleaned_data词典中额外添加的字段的数据。这是由自定义RegisterSerializer中的get_cleaned_data方法返回的字典。
在上面的save_user方法中,我们可以使用此数据并将其保存到适当的字段中,如下所示:
user.preferred_locale = data.get('preferred_locale')
Run Code Online (Sandbox Code Playgroud)
告诉Django使用此新适配器
settings.py:
ACCOUNT_ADAPTER = 'users.adapter.CustomAccountAdapter'
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用django-rest-auth注册端点'/ rest-auth / registration /'注册用户,并发送添加的其他字段的数据。这将全部保存在一个请求中。
同样,我意识到需要为每个字段添加自定义验证。但这是我以后将要探讨的另一个主题,当我发现它的工作原理时,将对其进行更新。
让我们打破你的问题。Django REST Framework
请注意,我正在向您解释基本知识。
User
模型:您做到了这一点。选择?是的。OneToOneForeignKey
创建一个指向模型的模型User
。CustomUserModel
. 为此,您需要AUTH_USER_MODEL
在settings.py
链接到官方文档中设置您已执行此操作。UserManager
用于处理用户的注册等信息。你还没有做到这一点。serializer
明确提及您期望最终用户提供的所有必填字段的字段。serializer.ModelSerializer
如果没有自定义字段,您甚至可以使用。serializer
。如果需要,请使用def validate(self, attrs)
。这是官方文档链接。APIView
因为您希望使用UserManager
上面创建的视图来注册用户。我还可以向您推荐一个我自己构建的应用程序。这是链接:DRF-USER。我User
在某种程度上定制了模型并遵循相同的过程。
希望这可以帮助。
归档时间: |
|
查看次数: |
1403 次 |
最近记录: |