这里写目录标题
- 一、创建子应用
- 二、用户注册设计
- 1、用户注册模型类设计
- a、Django认证系统提供了用户模型类User,为什么还要定义User模型类?
- b、AbstractUser
- c、自定义用户模型类的字段有
- d、User模型类编写好了就可以了吗?
- 2、用户注册序列化器类设计
- a、注意
- b、单字段进行校验
- c、用户认证的时候为什么不用create,而用create_user呢?
- d、代码展示
- 3、用户注册视图类设计
- a.注意
- b.APIView子类
- 4.路由配置
- a.特别注意:
- 三、用户验证
- 1、需要配置如下内容
- a、指定认证方式
- b、自定义JWT认证成功之后返回的响应格式
- c、截图所示
- 2、验证
一、创建子应用
一个项目往往会包含多个子应用,直接放在项目根目录不便于管理。
在当前目录的apps目录下创建子应用
python manage.py startapp users
优化导入路径
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
注册子应用
二、用户注册设计
1、用户注册模型类设计
a、Django认证系统提供了用户模型类User,为什么还要定义User模型类?
Django认证系统提供了用户模型类User,具体位置:django.contrib.auth.models.User;
因为Django认证系统提供的用户模型类User中缺少我本次项目中需要的字段,需要重写定义User模型类,最好不要和User重名,我以UserModel命令
b、AbstractUser
自定义的User需要继承AbstractUser,同时还需要继承BaseModel
AbstractUser源码如下:
class AbstractUser(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
.....
class User(AbstractUser):
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
c、自定义用户模型类的字段有
mobile
代码如下
import re
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
mobile = models.CharField('电话号码',
max_length=20,
help_text='电话号码',
null=True, blank=True,
)
class Meta:
db_table = 't_user'
verbose_name = '用户表'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
REQUIRED_FIELDS = ['mobile'] # 再通过createsuperuser管理命令创建用户时,将提示输入mobile字段
d、User模型类编写好了就可以了吗?
当然不是了,Django不会识别到你自己定义的User模型类,此时Django还是识别系统自带的User模型类,那需要怎么做
需要在settings.py配置文件中配置
特别注意:添加自定义用户模型类(应用名字.模型类名)
AUTH_USER_MODEL='users.User'
2、用户注册序列化器类设计
a、注意
1、extra_kwargs:当对模型类中定义的字段进行细微的调整时,在序列化器类中使用extra_kwargs进行调整
2、模型类中字段如果有设置为unique=True时,当校验不通过,在序列化输出时,并不是我想要的校验结果,可以通过
"validators": [UniqueValidator(queryset=UserModel.objects.all(), message='用户名已注册,请重新输入')]
,进行自定义.
3、一定要记住password字段,一定不能输出,要设置为’write_only’: True,
b、单字段进行校验
当在extra_kwargs={}中没法进行细微的调整时,需要进行单字段校验
采用validate_属性名称
例如当对手机号进行校验时,
用validate_phone(attr)
必须返回attr
拓展:
多字段校验:validate(attrs)
c、用户认证的时候为什么不用create,而用create_user呢?
UserModel.objects.create(**validated_data)
:
create:只会将反序列化输入校验通过的字段,原样插入到数据库中,因为密码是不能直接插入到数据中的
所以必须要重写create方法.
代码如下:
def create(self,validated_data):
'''必须重写create函数,因为用户密码是不能直接插入到数据库的'''
user=UserModel.objects.create_user(**validated_data)
return user
d、代码展示
import re
from rest_framework.validators import UniqueValidator, ValidationError
from rest_framework import serializers
from .models import User
class RegisterSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(write_only=True,
label='确认密码',
help_text='确认密码',
min_length=6,
max_length=20,
error_messages={
'min_length': '仅允许6-20个字符的密码',
'max_length': '仅允许6-20个字符的密码'
})
class Meta:
model = User
fields = ['id', 'username', 'password', 'mobile', 'email', 'password_confirm']
extra_kwargs = {
'username': {
'label': '用户名',
'help_text': '用户名',
'min_length': 2,
'max_length': 20,
'error_messages': {
'min_length': '仅允许2-20个字符的密码',
'max_length': '仅允许2-20个字符的密码'
}
},
'password': {
'label': '密码',
'help_text': '密码',
'write_only': True,
'min_length': 6,
'max_length': 20,
'error_messages': {
'min_length': '仅允许6-20个字符的密码',
'max_length': '仅允许6-20个字符的密码'
}
},
'email': {
'label': '邮箱',
'help_text': '邮箱',
'required': True,
'allow_blank': True,
'validators': [
UniqueValidator(queryset=User.objects.all(), message='此邮箱已注册')
]
}
}
def validate_mobile(self, value):
if not re.match(r'1[3-9]\d{9}', value):
raise ValidationError("手机号码格式不正确")
return value
def validate(self, attrs):
password = attrs.get('password')
password_confirm = attrs.get('password_confirm')
if not password == password_confirm:
raise serializers.ValidationError('您2次输入的密码不一致')
return attrs
def create(self, validated_data):
validated_data.pop('password_confirm')
# 调用create_user方法,处理密码加密的问题
return User.objects.create_user(**validated_data)
3、用户注册视图类设计
a.注意
当视图类中需要用的接口包括增删改查查时,不用想直接继承ModelViewSet即可
当视图类中只实现某1个功能,只需要继承特定的视图类即可,不能继承ModelViewSet.
因为会有漏洞,不法分子会恶意访问接口进行修改数据.
b.APIView子类
ListAPIView
CreateAPIView
UpdateAPIView
RetrieveAPIView
DestroyAPIView
ListCreateAPIView
RetrieveUpdateAPIView
RetrieveDestroyAPIView
RetrieveUpdateDestroyAPIView
from django.shortcuts import render
# Create your views here.
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework import generics
from .models import User
from .serializers import RegisterSerializer
class UserRegisterView(generics.CreateAPIView):
queryset = User.objects.all()
serializer_class = RegisterSerializer
4.路由配置
from django.urls import path,include
from . import views
from rest_framework import routers
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns=[
path('users/login/',obtain_jwt_token),
path('register/',views.UserRegisterView.as_view())
a.特别注意:
当数据库脚本生成和迁移操作时,如果数据库中没有生成对应的表,
首先需要检查模型类设计是否正确;
接着将迁移脚本都删除,同时将数据库中的表也删除
重新执行迁移脚本(init.py文件不要删)
三、用户验证
1、需要配置如下内容
a、指定认证方式
REST_FRAMEWORK = {
# 指定使用的认证类
# a、在全局指定默认的认证类(认证方式)
'DEFAULT_AUTHENTICATION_CLASSES': [
# 1、指定jwt token认证
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
],
# 'DEFAULT_PERMISSION_CLASSES':(
# 'erp_project.utils.rbac_permissions.RbacPermission'
# )
# 过滤
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
# JWT配置
JWT_AUTH = {
# 指定token失效时间为1天
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
# 使用自己的jwt_response_payload_handler,目的是响应结果中可以返回用户名和id
'JWT_RESPONSE_PAYLOAD_HANDLER': 'utils.jwt_handler.jwt_response_payload_handler',
}
b、自定义JWT认证成功之后返回的响应格式
def jwt_response_payload_handler(token, user=None, response=None):
'''自定义JWT认证成功之后返回的响应格式'''
return {
'id': user.id, # 返回登录用户的id
'username': user.username, # 用户名
'token': token
}
c、截图所示