首页 > 其他分享 >django+drf开发一些个人的标准化

django+drf开发一些个人的标准化

时间:2023-09-02 10:34:30浏览次数:36  
标签:username mobile 标准化 django user import validated data drf

最近在改造一下个人的开发风格。特分享一下。

  • 子应用我一般放在apps中,每个不同模块的子应用起不同的名字。startapp后自己移动一下,记得修改一下Appconfig中的name即可。
  • 子应用中创建services.py或者如有需要可以创建services模块再细分。所有业务放到services中编写。
  • views一律改成apis.py,将views中的业务分割services.py中。
  • 序列化器中一般不写业务相关代码。
  • 提供一个ApiResponse做统一返回,自己继承DRF的response改写一下即可。配合自己异常类,以及全局的异常枚举状态信息。
  • 另外也要改写全局异常捕获处理。做异常统一格式输出。

这里举例一个子应用User。

# apps.users.drf.apis.py
from django.contrib.auth import logout
from rest_framework import serializers
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.request import Request
from rest_framework.views import APIView

from apps.users.drf.services import (
    user_get_login_data,
    user_login,
    user_mobile_exist,
    user_register,
    user_username_exist
)
from utils.drf import ApiResponse
from utils.exception.statuscode import GlobalStatusCode


# 用户注册API
class RegisterApi(APIView):
    permission_classes = (AllowAny,)

    # 将序列化器单独定义在api内中,尽量减少重用序列化器
    class RegisterInputSerializer(serializers.Serializer):
        username = serializers.CharField(required=True)
        password = serializers.CharField(required=True)
        password2 = serializers.CharField(required=True)
        mobile = serializers.CharField(required=True)
        allow = serializers.CharField(required=True)
        sms_code = serializers.CharField(required=True, min_length=6, max_length=6)

    def post(self, request: Request):
        serializer = self.RegisterInputSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        # 调用服务层的方法
        user = user_register(request, serializer.validated_data)

        return ApiResponse(GlobalStatusCode.OK if user else GlobalStatusCode.REGISTER_FAILED_ERR)


# 用户登录api
class LoginApi(APIView):
    permission_classes = (AllowAny,)

    class UserLoginSerializer(serializers.Serializer):
        username = serializers.CharField()
        password = serializers.CharField()

    def post(self, request: Request):
        serializer = self.UserLoginSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        user = user_login(request, serializer.validated_data)
        data = user_get_login_data(user=user)
        
        return ApiResponse(GlobalStatusCode.OK, data=data)


# 用户登出api
class LogoutApi(APIView):
    permission_classes = (IsAuthenticated,)

    def post(self, request: Request):
        # 这种就没必要再services.py中定义函数来调用业务了,本身就一行简单的业务代码。
        logout(request)
        
        return ApiResponse(GlobalStatusCode.OK)


服务层services.py

# apps/user/drf/services.py
import re

from django.contrib.auth import authenticate, login
from django.db.models import Q
from django_redis import get_redis_connection
from redis import Redis

from apps.users.models import User
from utils.exception.drf import BusinessException
from utils.exception.statuscode import GlobalStatusCode
from utils.regexstring import PHONENUM,PASSWORD,USERNAME


def user_username_exist(username):
    """判断用户名是否存在"""
    return User.objects.filter(username=username, is_superuser=False).count() > 1


def user_mobile_exist(mobile):
    """判断手机号是否存在"""
    return User.objects.filter(mobile=mobile, is_superuser=False).count() > 1


def user_register(request, validated_data) -> User:
    """用户注册业务逻辑"""

    username = validated_data['username']
    mobile = validated_data['mobile']
    sms_code = validated_data['sms_code']

    # 先校验是否勾选协议,因为不勾选全是白瞎,没必要浪费性能区校验这个那个的..
    if validated_data['allow'] != '1':
        raise BusinessException(GlobalStatusCode.ALLOW_ERR)

    # 判断两次输入的密码是否一致
    if validated_data['password'] != validated_data['password2']:
        raise BusinessException(GlobalStatusCode.CPWD_ERR)

    # 只需要校验密码是否符合规定就可以了,确认密码不要校验规则,只需要和密码判断是否相同。
    if re.match(PASSWORD, validated_data['password']) is None:
        raise BusinessException(detail='密码格式不符合规定')

    if re.match(USERNAME, username) is None:
        raise BusinessException(GlobalStatusCode.USER_ERR)

    if re.match(PHONENUM, mobile) is None:
        raise BusinessException(GlobalStatusCode.MOBILE_ERR)

    # 判断用户是否已注册
    user_count = User.objects.filter(Q(username=username) | Q(mobile=mobile)).count()
    if user_count > 0:
        raise BusinessException(detail='用户已经注册')

    # 校验短信验证码
    from django.conf import settings
    if settings.DEBUG:
        pass
        # 测试环境直接跳过校验验证码
        print('测试跳过验证码..')
    else:
        redis_connection: Redis = get_redis_connection()
        code_from_redis = redis_connection.get(validated_data['mobile'])
        if code_from_redis is None:
            raise BusinessException(detail='短信验证码已过期!请重新获取!')

        if code_from_redis.decode() != sms_code:
            raise BusinessException(detail='短信验证码不正确!请重新输入!')

    user = User.objects.create_user(
        username=validated_data['username'],
        password=validated_data['password'],
        mobile=validated_data['mobile']
    )

    # 登录
    login(request, user)

    return user


def user_get_login_data(*, user: User):
    return {
        "id": user.id,
        "mobile": user.mobile,
        "username": user.username,
        "email": user.email,
        "is_superuser": user.is_superuser,
    }


def user_login(request, validated_data):
    username = validated_data['username']

    if re.match(PHONENUM, username) is not None:
        User.USERNAME_FIELD = "mobile"

    user = authenticate(**validated_data)

    if user is None:
        raise BusinessException(GlobalStatusCode.PWD_ERR)

    login(request, user)

    return user


标签:username,mobile,标准化,django,user,import,validated,data,drf
From: https://www.cnblogs.com/juelian/p/17673286.html

相关文章

  • 同时创建作者和作者详情表,ModelSerializer使用,模块与包的使用,反序列化校验源码分析
    1同时创建作者和作者详情表1.1django项目改名字后顺利运行#1先改文件夹名#2改项目名#3改项目内的文件夹名#4替换掉所有文件中的drf_day04---》drf_day05#5命令行中启动:pythonmanage.pyrunserver#6setting--->django--->指定项目根路径1.1作者......
  • 同时创建一对一表关系字段(作者和作者详情为例)、ModelSerializer使用、模块与包的使用
    同时创建一对一表关系字段(作者和作者详情为例)序列化器#作者表序列化类classAuthorSerializer(serializers.Serializer):name=serializers.CharField(max_length=32)age=serializers.IntegerField()sex=serializers.CharField(max_length=16)addr......
  • drf-序列化组件
    一、序列化组件介绍基于原生django写接口:json格式数据要自己序列化,urlencoded:传过来的数据要用for循环来取出值,在定义成字典的形式,比较麻烦。借助于drf提供的序列化组件来完成快速序列化使用步骤:1先在配置文件中注册:INSTALLED_APPS=['rest_fram......
  • drf-day3
    内容回顾1、前端编码格式urlencoded:body体中:username=lqz&password=123 django 的request.POST取出值json格式:body体中:{"username":"lqz","password":"123"} django 的request.POST取不出值,从request.body-->自己做反序列化form-data:body中......
  • restful规范和django源码写接口
    一、restful规范1、restful规范是什么,如何来的?一种定义WebAPI接口的设计风格,尤其适用于前后端分离的应用模式中的规范RoyFielding的博士论文提出的2、以后写接口,大致都要遵循如下规范-1数据的安全保障-》url链接一般都采用https协议进行传输--》它比http安全......
  • Python drf day02
    restful规范restful规范是什么,如何来的?是一种定义WebAPI接口的设计风格,尤其适用于前后端分离的应用模式中的规范RoyFielding的博士论文提出的restful规范的具体内容1.数据的安全保障--》url链接一般都采用https协议进行传输,它比http安全2.接口特征表现--》url中带api......
  • drf-restful规范
    RESTfulAPI规范简介: REST全称是RepresentationalStateTransfer,中文意思是表述(编者注:通常译为表征性状态转移)。它首次出现在2000年RoyFielding的博士论文中。""" RESTful是一种定义WebAPI接口的设计风格,尤其适用于前后端分离的应用模式中。"""这种风格的理念认为后端......
  • drf入门
    drf入门规范1、Web开发模式​ 1.1、前后端混合开发模式:​ 1.2、前后端分离开发模式2、API接口#api接口:通过网络,规定了前后端信息交互规则的url链接,也就是前后端信息交互的媒介 -https://www.baidu.com/books/--->json格式数据--->接口#拿到的是json格式的数据 -https......
  • django自带的cache缓存框架使用
    https://docs.djangoproject.com/zh-hans/4.2/topics/cache/#top主要步骤官网也写得很清楚了,包含怎么区使用。这里就展示一些配置django-redis来使用#settings.pyCACHES={'default':{#默认,预留'BACKEND':'django_redis.cache.RedisCache','......
  • Django CMS搭建--1.虚拟环境搭建
    客户端环境:windows101.virtualenv使用virtualenv是Python中的一个包,用于创建和管理虚拟环境,可以在不同的项目中使用不同的Python版本和第三方库,避免了全局环境和项目之间的冲突。1.1命令行cmd安装:pipinstallvirtualenv1.2创建虚拟环境myvenv,激活后,你会看到命令行前......