上一章:
Django实现接口自动化平台(二)认证&授权&登录【持续更新中】_做测试的喵酱的博客-CSDN博客
下一章:
一、背景
1.1 实现功能
1、一共提供三个接口:
使用Django 自带的User模型,实现注册功能。
实现对用户名的唯一校验
实现对邮箱的唯一校验
2、注册接口
接收字段:
- 用户名username
- 密码 password
- 确认密码 password_confirm
- 邮箱 email
返回字段:
- token
- id
- username
1.2 分析
1、使用Django 自带的User模型,实现注册功能。所以不需要再创建User数据库模型,只需要创建对应的注册序列化器类就可以了。
二、创建Users应用
1、创建users应用
python3 manage.py startapp users
2、注册users应用,在setting.py文件中,注册users
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users'
]
三、序列化器类
相关知识点,可参考:
五、DRF 模型序列化器ModelSerializer_做测试的喵酱的博客-CSDN博客
创建注册相关的序列化器类
1、在Users下,新建 serializer.py文件。
3.1 序列化器类
3.1.1 代码
# -*- coding:utf-8 -*-
# @Author: 喵酱
# @time: 2023 - 05 -31
# @File: serializer.py
# desc:
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from rest_framework.validators import UniqueValidator
from django.contrib.auth.models import User
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
class RegisterSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(label='确认密码', help_text='确认密码',
min_length=6, max_length=20,
write_only=True,
error_messages={
'min_length': '仅允许6~20个字符的确认密码',
'max_length': '仅允许6~20个字符的确认密码', })
token = serializers.CharField(label='生成token', help_text='生成token', read_only=True)
class Meta:
# 指定模型
model = User
fields = ('id', 'username', 'password', 'email', 'password_confirm', 'token')
extra_kwargs = {
'username': {
'label': '用户名',
'help_text': '用户名',
'min_length': 6,
'max_length': 20,
'error_messages': {
'min_length': '仅允许6-20个字符的用户名',
'max_length': '仅允许6-20个字符的用户名',
}
},
'email': {
'label': '邮箱',
'help_text': '邮箱',
'write_only': True,
'required': True,
# 添加邮箱重复校验
'validators': [UniqueValidator(queryset=User.objects.all(), message='此邮箱已注册')],
},
'password': {
'label': '密码',
'help_text': '密码',
'write_only': True,
'min_length': 6,
'max_length': 20,
'error_messages': {
'min_length': '仅允许6-20个字符的密码',
'max_length': '仅允许6-20个字符的密码',
}
}
}
def validate(self, attrs):
if attrs.get('password') != attrs.get('password_confirm'):
raise serializers.ValidationError('密码与确认密码不一致')
attrs.pop('password_confirm')
return attrs
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
# 创建payload
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
user.token = token
return user
3.1.2 分析
1、查看User数据库模型源码,本身有username、email 等字段。
但是缺少我们注册需要的 确认密码password_confirm 与token字段。
所在在定义序列化器类时,需要定义类属性
class RegisterSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(label='确认密码', help_text='确认密码',
min_length=6, max_length=20,
write_only=True,
error_messages={
'min_length': '仅允许6~20个字符的确认密码',
'max_length': '仅允许6~20个字符的确认密码', })
token = serializers.CharField(label='生成token', help_text='生成token', read_only=True)
其他自带的字段,直接在内部类Meta下,extra_kwargs 下,做描述。
2、实现密码与确认密码的联合校验
def validate(self, attrs):
if attrs.get('password') != attrs.get('password_confirm'):
raise serializers.ValidationError('密码与确认密码不一致')
attrs.pop('password_confirm')
return attrs
确认密码最后要pop掉,因为数据库User表里没有这个字段。
3、创建用户并返回token
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
# 创建payload
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
user.token = token
return user
先创建user用户,再生成token,最后将user添加token属性,将user返回。
四、创建视图 & 定义路由
创建视图相关知识点:
八、(重点)视图集ModelViewSet&自定义action&路由routers_做测试的喵酱的博客-CSDN博客
4.1 方式一:视图通过继承generics.CreateAPIView实现
4.1.1 继承generics.CreateAPIView实现视图
class UserView(generics.CreateAPIView):
"""
"""
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
4.1.2 创建路由
from django.urls import path, include, re_path
from rest_framework import routers
from rest_framework_jwt.views import obtain_jwt_token
from . import views
urlpatterns = [
# path('user/register/', views.UserView.as_view()),
]
4.2 方式二
4.2.1 视图
from rest_framework import mixins
from rest_framework import generics
from rest_framework import viewsets
from rest_framework.views import APIView
from django.contrib.auth.models import User
from rest_framework.response import Response
from django.contrib.auth.models import User
from .serializer import RegisterSerializer
# class UserView(mixins.CreateModelMixin, generics.GenericAPIView):
# class UserView(generics.CreateAPIView):
# """
#
# """
# def post(self, request, *args, **kwargs):
# return self.create(request, *args, **kwargs)
class UserView(mixins.CreateModelMixin, viewsets.GenericViewSet):
"""
"""
queryset = User.objects.all()
serializer_class = RegisterSerializer
class UsernameIsExistedView(APIView):
def get(self, request, username):
count = User.objects.filter(username=username).count()
return Response({'username': username, 'count': count})
class EmailIsExistedView(APIView):
def get(self, request, email):
count = User.objects.filter(email=email).count()
return Response({'email': email, 'count': count})
4.2.2 路由
在子应用users下,定义注册的路由 'register/'
用户名校验的路由:r'^(?P<username>\w{6,20})/count/$',
邮箱唯一约束校验的路由:r'^(?P<email>[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)/count/$'
同时对登录的路由,进行一下修改。在上一章中,因为我们没有user子应用,所以把login路由直接定义在了全局urls.py中了。现在我们有了user子应用,就重新定义一下登录的路由。保证路由的统一性。
登录路由:path('login/', obtain_jwt_token),
from django.urls import path, include, re_path
from rest_framework import routers
from rest_framework_jwt.views import obtain_jwt_token
from . import views
# router = routers.SimpleRouter()
# router.register(r'users', views.UserView)
urlpatterns = [
# path('user/register/', views.UserView.as_view()),
path('register/', views.UserView.as_view({'post': 'create'})),
re_path(r'^(?P<username>\w{6,20})/count/$', views.UsernameIsExistedView.as_view()),
re_path(r'^(?P<email>[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)/count/$',
views.EmailIsExistedView.as_view()),
path('login/', obtain_jwt_token),
]
五、定义总路由
在全局urls.py中,设置user应用的路由
urlpatterns = [
path('user/', include('users.urls')),
]
注意:
需要把login登录的路由,在这里注释掉,统一使用 path('user/', include('users.urls')),
六、请求演示:
1、注册接口:
http://127.0.0.1:8000/user/register/
2、登录接口
3、用户名校验
用户已经存在