django+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
django+drf开发一些个人的标准化的更多相关文章
- django drf 开发 ~ models基础学习
零 介绍 对于ORM框架,可以简单的认为自定义类U表示数据库的表:根据类创建的对象表示数据库表一 数据表设计 1 类型统计 CharField->(string)->(1 ma ...
- django DRF理解
django restframework(DRF) 最近的开发过程当中,发现restframework的功能很强大,所以尝试解读了一下源码,写篇博客分享给大家,有错误的地方还请各位多多指出 视图部分 ...
- Python之路【第二十三篇】:Django 初探--Django的开发服务器及创建数据库(笔记)
Django 初探--Django的开发服务器及创建数据库(笔记) 1.Django的开发服务器 Django框架中包含一些轻量级的web应用服务器,开发web项目时不需再对其配置服务器,Django ...
- Django web 开发指南 no such table:
在学习django web开发指南时,发布新博客点击save后会有error提示:no such table balabalabala... 百度了一下说重新运行manage.py syncdb 就可 ...
- Django 初探--Django的开发服务器及创建数据库(笔记)
1.Django的开发服务器 Django框架中包含一些轻量级的web应用服务器,开发web项目时不需再对其配置服务器,Django提供的内置服务器可以在代码修改时自动加载,从而实现网站的迅速开发. ...
- 解决Django + DRF:403 FORBIDDEN:CSRF令牌丢失或不正确,{"detail":"CSRF Failed: CSRF cookie not set."}
我有一个Android客户端应用程序尝试使用Django + DRF后端进行身份验证.但是,当我尝试登录时,我收到以下响应: 403: CSRF Failed: CSRF token missing ...
- 在 Django/Flask 开发服务器上使用 HTTPS
使用 Django 或 Flask 这种框架开发 web app 的时候一般都会用内建服务器开发和调试程序,等程序完成后再移交到生产环境部署.问题是这些内建服务器通常都不支持 HTTPS,我们想在开发 ...
- Django Web开发学习笔记(1)
一.Python的标准类型 (1)bool型 >>> bool("") False >>> bool(None) False >>& ...
- Atitit 快速开发的推荐技术标准化 规范 大原则
Atitit 快速开发的推荐技术标准化 规范 大原则 1. 如何评估什么样的技术适合快速开发??1 1.1. (重要)判断语言层次..层次越高开发效率越高 4gl dsl> 3.5gl &g ...
- [置顶] Django 微信开发(一)——环境搭建
Django 微信开发(一)——环境搭建 随着移动互联网时代的到来,微信——一个改变着我们生活的产品悄悄走近了我们的生活.我们不得不觉得自己很幸运,自己能在这个世界上遇到像QQ.微博.微信这样优秀的产 ...
随机推荐
- 如何做一个api接口?
程序员是公司里的技术岗位,是产品经理最亲密的伙伴.但是程序员可以理解产品经理的工作,产品经理却不一定理解程序员的工作,所以经常被无良程序员欺骗.从API接口这个维度,分析API的概念以及为什么要了解它 ...
- Solution -「CF 888E」Maximum Subsequence
Description Link. 给一个数列和 \(m\),在数列任选若干个数,使得他们的和对 \(m\) 取模后最大. Solution 记录一下犯下的一个 nt 错误. 首先我们有一个显然的 D ...
- 200PLC转以太网与1200PLC实现PUT GET通信
200PLC转以太网与1200PLC实现PUT GET通信 本案例介绍西门子PLC200PLC 224或226,Port0或者是Port1串口通过兴达易控PPI-ETH-XD1.0plc以太网模块,2 ...
- ChatGPT 是如何产生心智的?
一.前言 - ChatGPT真的产生心智了吗? 来自斯坦福大学的最新研究结论,一经发出就造成了学术圈的轰动,"原本认为是人类独有的心智理论(Theory of Mind,ToM),已经出现在 ...
- python学习笔记(持续更新)
一.对列表的操作 #建立一个列表 list = [1,2,3,4] #打印列表 print(list) #在列表尾部添加元素 list.append(5) #在指定位置插入元素 list.insert ...
- mysql学习之数据备份和恢复
一.使用mysqldump进行备份 如:将test数据库备份到/tmp/mysql_back/目录下 [root@localhost tmp]# mysqldump -uroot -p111 -l - ...
- 【KMP】border 题解
题目描述 输入 输出 样例输入 abaabaa 样例输出 17 样例解释: f[2][a] = 1 f[3][a] = 1 f[4][a] = 1 f[4][b] = 2 f[5][a] = 1 f[ ...
- 数据结构与算法(LeetCode) 第二节 链表结构、栈、队列、递归行为、哈希表和有序表
一.链表结构 1.单向链表节点结构 public class Node{ public int value; public Node next; public Node(int data){ valu ...
- django 国际化
参考文档: https://docs.djangoproject.com/zh-hans/2.2/topics/i18n/translation/ https://blog.csdn.net/qq_3 ...
- [Python]常用知识
Python 常用知识 编译型语言 和 解释性语言 解释性语言 编译型语言 概念 计算机不能直接的理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言的编写的 ...