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

  • 子应用我一般放在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开发一些个人的标准化的更多相关文章

  1. django drf 开发 ~ models基础学习

    零 介绍  对于ORM框架,可以简单的认为自定义类U表示数据库的表:根据类创建的对象表示数据库表一 数据表设计  1 类型统计     CharField->(string)->(1 ma ...

  2. django DRF理解

    django restframework(DRF) 最近的开发过程当中,发现restframework的功能很强大,所以尝试解读了一下源码,写篇博客分享给大家,有错误的地方还请各位多多指出 视图部分 ...

  3. Python之路【第二十三篇】:Django 初探--Django的开发服务器及创建数据库(笔记)

    Django 初探--Django的开发服务器及创建数据库(笔记) 1.Django的开发服务器 Django框架中包含一些轻量级的web应用服务器,开发web项目时不需再对其配置服务器,Django ...

  4. Django web 开发指南 no such table:

    在学习django web开发指南时,发布新博客点击save后会有error提示:no such table balabalabala... 百度了一下说重新运行manage.py syncdb 就可 ...

  5. Django 初探--Django的开发服务器及创建数据库(笔记)

    1.Django的开发服务器 Django框架中包含一些轻量级的web应用服务器,开发web项目时不需再对其配置服务器,Django提供的内置服务器可以在代码修改时自动加载,从而实现网站的迅速开发. ...

  6. 解决Django + DRF:403 FORBIDDEN:CSRF令牌丢失或不正确,{"detail":"CSRF Failed: CSRF cookie not set."}

    我有一个Android客户端应用程序尝试使用Django + DRF后端进行身份验证.但是,当我尝试登录时,我收到以下响应: 403: CSRF Failed: CSRF token missing ...

  7. 在 Django/Flask 开发服务器上使用 HTTPS

    使用 Django 或 Flask 这种框架开发 web app 的时候一般都会用内建服务器开发和调试程序,等程序完成后再移交到生产环境部署.问题是这些内建服务器通常都不支持 HTTPS,我们想在开发 ...

  8. Django Web开发学习笔记(1)

    一.Python的标准类型 (1)bool型 >>> bool("") False >>> bool(None) False >>& ...

  9. Atitit 快速开发的推荐技术标准化 规范 大原则

    Atitit 快速开发的推荐技术标准化 规范 大原则 1. 如何评估什么样的技术适合快速开发??1 1.1. (重要)判断语言层次..层次越高开发效率越高  4gl  dsl> 3.5gl &g ...

  10. [置顶] Django 微信开发(一)——环境搭建

    Django 微信开发(一)——环境搭建 随着移动互联网时代的到来,微信——一个改变着我们生活的产品悄悄走近了我们的生活.我们不得不觉得自己很幸运,自己能在这个世界上遇到像QQ.微博.微信这样优秀的产 ...

随机推荐

  1. 实现WebRTC群聊会议室(Mesh方案)

    近期需要做一个类似会议室功能,但网络上大多数是一对一通信,故记录分享希望帮助到有用的人 WebRTC一对一聊天原理 关于WebRTC建立一对一聊天的模板网上很多,可参考以下博客:springboot+ ...

  2. ContentPresenter使用DataTemplate

    在使用自定义样式内容时,有时也需要在自定义样式中绑定一下数据模板 可以使用ContentPresenter的ContentTemplate绑定定义好的资源 DateTemplate 用法代码如下 &l ...

  3. MongoDB 中使用 explain 分析创建的索引是否合理

    MongoDB 中如何使用 explain 分析查询计划 前言 查询计划 explain explain 1.queryPlanner 2.executionStats 3.allPlansExecu ...

  4. 基于 Wiki.js 搭建知识库系统

    前言 本文介绍如何使用 Wiki.js 搭建知识库系统. Wiki.js 官网 安装 前提准备 Wiki.js 几乎可以在任何支持 Node.js 的系统上运行.它可以运行在 Linux .Windo ...

  5. PLC通过Modbus转Profinet网关连接变频器控制电机案例

    在本案例中,通过使用Modbus转Profinet网关(XD-MDPN100),PLC可以通过Profinet协议与变频器进行通信和控制.这样,PLC可以实现对电机的转速调节.启停控制等功能. 同时, ...

  6. C++ RAII在HotSpot VM中的重要应用

    RAII(Resource Acquisition Is Initialization),也称为"资源获取就是初始化",是C++语言的一种管理资源.避免泄漏的惯用法.C++标准保证 ...

  7. MySQL实战实战系列 04 深入浅出索引(下)

    在上一篇文章中,我和你介绍了 InnoDB 索引的数据结构模型,今天我们再继续聊聊跟 MySQL 索引有关的概念. 在开始这篇文章之前,我们先来看一下这个问题: 在下面这个表 T 中,如果我执行 se ...

  8. SpringBoot进阶教程(七十七)WebSocket

    WebSocket是一种在单个TCP连接上进行全双工通信的协议.WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在WebSocket API中,浏览器和 ...

  9. c语言代码练习10

    //判断输入的数字是否为素数#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int n = 0; int ...

  10. Speex详解(2019年09月25日更新)

    Speex详解 整理者:赤勇玄心行天道 QQ号:280604597 微信号:qq280604597 QQ群:511046632 博客:www.cnblogs.com/gaoyaguo 大家有什么不明白 ...