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
    评论
Django-rest-framework是一个用于构建Web API的强大框架,它提供了许多有用的工具和库,可以帮助我们轻松地构建出一个安全可靠的用户注册和登录系统。 下面是一个简单的Django-rest-framework用户注册与登录的实现: 首先,我们需要安装Django-rest-framework: ``` pip install djangorestframework ``` 接着,我们需要在settings.py文件中添加以下配置: ```python INSTALLED_APPS = [ # ... 'rest_framework', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], } ``` 上面的配置将启用TokenAuthentication身份验证和IsAuthenticated权限,这将确保只有已登录的用户才能访问我们的API。 现在,我们可以创建一个名为"users"的Django应用程序,并定义以下模型: ```python from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): pass ``` 接着,我们需要定义序列化器来将User模型转换为JSON格式: ```python from rest_framework import serializers from .models import User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('username', 'email', 'password') extra_kwargs = {'password': {'write_only': True}} def create(self, validated_data): user = User.objects.create_user( username=validated_data['username'], email=validated_data['email'], password=validated_data['password'] ) return user ``` 上面的代码定义了一个UserSerializer序列化器,将User模型转换为JSON格式。我们使用Meta类来指定模型和要序列化的字段,以及一些额外的参数。在create方法中,我们使用create_user方法创建新用户。 现在,我们可以定义视图来处理用户注册和登录请求: ```python from rest_framework import generics, permissions, status from rest_framework.response import Response from rest_framework.authtoken.models import Token from rest_framework.views import APIView from django.contrib.auth import authenticate, login from .models import User from .serializers import UserSerializer class RegisterView(generics.CreateAPIView): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [permissions.AllowAny] def post(self, request): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) class LoginView(APIView): permission_classes = [permissions.AllowAny] def post(self, request): username = request.data.get('username') password = request.data.get('password') user = authenticate(request, username=username, password=password) if user is not None: login(request, user) token, created = Token.objects.get_or_create(user=user) return Response({'token': token.key}) else: return Response({'error': 'Invalid credentials'}) ``` 上面的代码定义了RegisterView和LoginView视图。RegisterView视图处理用户注册请求,LoginView视图处理用户登录请求。我们在视图中使用UserSerializer序列化器来验证输入数据,并使用TokenAuthentication身份验证来保护API。 现在我们已经完成了用户注册和登录的实现。可以使用POST请求来测试我们的API: - 用户注册: ``` POST /api/register/ { "username": "testuser", "email": "testuser@example.com", "password": "testpassword" } ``` - 用户登录: ``` POST /api/login/ { "username": "testuser", "password": "testpassword" } ``` 如果登录成功,API将返回一个包含Token身份验证密钥的JSON响应。现在,我们可以将此密钥用于所有受保护的API请求中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值