Django项目--用户注册(个人练手)

一、定义用户模型类

1、Django默认用户认证系统

django.contrib.auth包含认证框架的核心和默认的模型,django.contrib.contenttypes是Django内容类型系统,它允许权限与你创建的模型关联。

2、Django默认用户模型类

Django认证系统用户模型类位置 django.contrib.auth.models.User 。一般情况下需要继承父类AbstractUser ,User对象必选属性有【username、password 】,可选属性有【email、first_name、last_name、last_login、date_joined、is_active 、is_staff、is_superuse 】,判断用户是否通过认证【is_authenticated 】。设置密码:set_password(raw_password),校验密码:check_password(raw_password) 。

3、自定义用户模型类:

在使用命令时如果app的名字是user会出现包冲突,建议包名改成users。然后再models.py中粘贴代码。只要使用了models就需要在dev文件的INSTALLED_APPS注册一下。

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

# Create your models here.


class User(AbstractUser):
    """自定义用户模型类"""
    mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号') #unique指定唯一值

    class Meta:
        db_table = 'tb_users'  #指定表的名字
        verbose_name = '用户'  #设置模型在admin站点显示的中文名
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

还需要在dev文件中加入配置

AUTH_USER_MODEL = '应用名.模型类名'
AUTH_USER_MODEL = 'auth.User'  #User是模型的名字

4、在urls中加入路由

# 用户名是否注册
    re_path(r'usernames/(?P<username>\w{5,20})/count/', views.UsernameCountView.as_view()),

二、短信验证码

1、业务过程

  1. 生成和发送短信验证码

  2. 保存短信验证码

  3. redis pipeline的使用

  4. 检查是否在60s内有发送记录

2、后端实现

短信验证码需要企业才可以发送,我们只是为了实现相应的功能逻辑。

redis配置我在前面已经说过,使用这里就直接使用,只需要在之前的dev配置redis代码中加入。

"verify_codes": {  # 存储验证码
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/2",  #如果redis在虚拟机中记得修改
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },

生成和发送短信验证码、保存短信验证码、redis pipeline的使用、检查60秒内是否发送。在views.py文件写入代码。短信验证的实现主要是在写入redis数据库时写入两条数据,一个是send_flag_手机号当做发过短信的标记和加上60秒的过期时间,另一个是sms_手机号:验证码,设置过期时间。

from django_redis import get_redis_connection
from random import randint
import logging

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from .constants import *

logger = logging.getLogger('django')


class SMSCodeView(APIView):
    """短信验证码"""

    def get(self, request, mobile):
        """
        @param mobile:  手机号
        """
        # 创建redis连接对象
        redis_conn = get_redis_connection('verify_codes')  # verify_codes 是配置里面的CACHES字段
        # 先从redis获取发送的标记
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        # 如果取到了标记,说明此手机号频繁发短信
        if send_flag:
            return Response({'message': '手机频繁发送短信'}, status=status.HTTP_400_BAD_REQUEST)

        # 生成验证码
        sms_code = '%06d' % randint(0, 999999)
        logger.info(sms_code)

        # 创建redis管道:(把多次redis操作装入管道中,将来一次性去执行,减少redis的连接操作)
        pl = redis_conn.pipeline()
        # 把验证码存储到redis数据库
        # redis_conn.setex('sms_%s' % mobile, SMS_CODE_REDIS_EXPIRES, sms_code)
        pl.setex('sms_%s' % mobile, SMS_CODE_REDIS_EXPIRES, sms_code)
        # 存储一个标记,表示手机号已发送过短信 标记有效期60s
        # redis_conn.setex('send_flag_%s' % mobile, SEND_SMS_CODE_INTERVAL, 1)
        pl.setex('send_flag_%s' % mobile, SEND_SMS_CODE_INTERVAL, 1)
        # 执行管道
        pl.execute()

        # 响应
        return Response({'message': 'ok'})

3、在urls加上路由

re_path是一个带有正则path

# 手机号是否注册
    re_path(r'mobiles/(?P<mobile>1[3-9]\d{9})/count/', views.MobileCountView.as_view()),

三、解决跨域问题

因为代码是前后端分离的,所以我们需要为后端添加跨域访问的支持。

参考文档https://github.com/ottoyiu/django-cors-headers/

1、安装

pip install django-cors-headers

2、dev中配置修改

添加应用

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)

中间层设置

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

添加白名单 (任意位置),凡是出现在白名单中的域名,都可以访问后端接口,CORS_ALLOW_CREDENTIALS 指明在跨域访问中,后端是否支持对cookie的操作。

# CORS
CORS_ORIGIN_WHITELIST = (
    '127.0.0.1:8080',
    'localhost:8080',
)
CORS_ALLOW_CREDENTIALS = True  # 允许携带cookie

四、用户注册

后端对于前端返回的数据大部分都需要校验。

1、创建serializers.py文件,创建序列化器检验数据

使用rest_framework包中的serializers。在创建视图类的时候视图类需要继承serializers.ModelSerializer,使用ModelSerializer是因为我们验证的是数据库的中数据字段

class CreateUserSerializer(serializers.ModelSerializer):
    """
    创建用户序列化器
    """
    password2 = serializers.CharField(label='确认密码', write_only=True)
    sms_code = serializers.CharField(label='短信验证码', write_only=True)
    allow = serializers.CharField(label='同意协议', write_only=True)

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'password2', 'sms_code', 'mobile', 'allow')
        extra_kwargs = {
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的用户名',
                    'max_length': '仅允许5-20个字符的用户名',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }

    def validate_mobile(self, value):
        """验证手机号"""
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式错误')
        return value

    def validate_allow(self, value):
        """检验用户是否同意协议"""
        if value != 'true':
            raise serializers.ValidationError('请同意用户协议')
        return value

    def validate(self, data):
        # 判断两次密码
        if data['password'] != data['password2']:
            raise serializers.ValidationError('两次密码不一致')

        # 判断短信验证码
        redis_conn = get_redis_connection('verify_codes')
        mobile = data['mobile']
        real_sms_code = redis_conn.get('sms_%s' % mobile)
        if real_sms_code is None:
            raise serializers.ValidationError('无效的短信验证码')
        if data['sms_code'] != real_sms_code.decode():
            raise serializers.ValidationError('短信验证码错误')

        return data

    def create(self, validated_data):
        """
        创建用户
        """
        # 移除数据库模型类中不存在的属性
        del validated_data['password2']
        del validated_data['sms_code']
        del validated_data['allow']
        user = super().create(validated_data)

        # 调用django的认证系统加密密码
        user.set_password(validated_data['password'])
        user.save()

        return user

2、在urls中加上路由

# 注册用户
    path('users/', views.UserView.as_view()),

3、常见知识点

read_only:只用于序列化输出使用
write_only:只用于但序列化输入时使用
super():将方法重写之后重新调用父类的该方法

如果继承了ModelSerializer,就需要在Meta类中指明模型 ,fields是选出我们需要检验的字段,extra_kwargs可以对一些字段加上约束条件,也可以在创建序列化器是直接校验。

    class Meta:
        model = User  # 从User模型中映射出序列化字段
        fields = ['id', 'username', 'password', 'password2', 'mobile', 'sms_code', 'allow', 'token']
        extra_kwargs = {  # 修改字段选项
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {  # 自定义校验出错后的错误信息提示
                    'min_length': '用户名长度不小于5',
                    'max_length': '用户名长度不大于20',
                }
            }

        }

  • 36
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值