持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
大家好~我是小方,欢迎大家关注笋货测试笔记体完记得俾个like呀
接上篇
上篇我们讲了后端服务添加日志,日志功能很重要的哦,记录报错信息,分析报错原因,解决报错~今天我们来编写第一个接口--注册接口
创建数据库
之前我们有说过,数据库采用的是MySQL,那么我们先创建数据工厂的数据库。
CREATE DATABASE IF NOT EXISTS datafactory DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
这个命令是指,当datafactory数据库不存在时,建立utf8mb4编码的数据库。
连接数据库配置
先安装sqlalchemy
和PyMySQL
pip3 install SQLAlchemy==1.4.23
pip3 install PyMySQL==1.0.2
在app/models/__init__.py
文件引入sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from config import Config
# Base是用来给模型类继承的
Base = declarative_base()
#创建同步数据库引擎
engine = create_engine(Config.SQLALCHEMY_DATABASE_URI, pool_recycle=7200, pool_pre_ping=True)
#创建会话,autocommit自动提交,autoflush 自动刷新,bind 绑定创建的引擎
Session = sessionmaker(bind=engine)
#向数据库发出建表完成类与表的映射
Base.metadata.create_all(engine)
表设计
先到config.py
文件下新建一个权限枚举类
class Permission(object):
MEMBERS = 0 # 普通用户
LEADER = 1 # 组长
ADMIN = 2 # 超管
app/models
下创建user.py
from datetime import datetime
from sqlalchemy import Column, String, INT, DATETIME, SMALLINT, func, Boolean
from app.models import Base
from config import Permission
class DataFactoryUser(Base):
__tablename__ = "data_factory_user"
id = Column(INT, primary_key=True, comment="主键id")
username = Column(String(16), unique=True, nullable=False, comment="用户名")
name = Column(String(16), nullable=True, comment="姓名")
password = Column(String(32), unique=False, comment="密码(md5加密)")
email = Column(String(128),unique=True, nullable=True, comment="邮箱号")
role = Column(SMALLINT, default=0, comment="0: 普通用户 1: 组长 2: 超管")
last_login_time = Column(DATETIME, nullable=True, comment="上次登录时间")
is_valid = Column(Boolean, nullable=False, default=False, comment="是否冻结")
create_time = Column(DATETIME, nullable=False, comment="创建时间")
update_code = Column(String(20), nullable=True, comment="更新人编码")
update_name = Column(String(20), nullable=True, comment="更新人")
update_time = Column(DATETIME, onupdate=func.now(), nullable=False, comment="更新时间")
def __init__(self, username, name, password, email):
self.username = username
self.name = name
self.password = password
self.email = email
self.role = Permission.MEMBERS
self.is_valid = False
self.create_time = datetime.now()
self.update_time = datetime.now()
self.last_login_time = datetime.now()
上面就是用户表的基础字段,用户名、密码、姓名、邮箱号、用户角色(不同角色拥有不同的权限)、是否冻结(封禁账号),其他的都是比较基本的,暂不介绍哈~
注册功能实现
在curd
目录下新建user
目录,接着在user
目录新建UserDao.py
文件
UserDao.py
实现逻辑
from app.models import Session
from sqlalchemy import or_, func
from app.models.user import DataFactoryUser
from app.utils.logger import Log
from config import Permission
class UserDao(object):
log = Log('UserDao')
@classmethod
def register_user(cls, username: str, name: str, password: str, email: str) -> None:
"""
:param username: 用户名
:param name: 姓名
:param password: 密码
:param email: 邮箱号
:return:
"""
try:
with Session() as session:
# 先查询用户名或邮箱号是否重复
users = session.query(DataFactoryUser).filter(or_(DataFactoryUser.username == username, DataFactoryUser.email == email)).first()
if users:
raise Exception('用户名或邮箱号重复')
# 统计用户表的用户数
count = session.query(func.count(DataFactoryUser.id)).group_by(DataFactoryUser.id).count()
user = DataFactoryUser(username, name, password, email)
# 如果第一个进来,默认是管理员权限
if count == 0 :
user.role = Permission.ADMIN
session.add(user)
session.commit()
except Exception as e:
cls.log.error(f"用户注册失败: {str(e)}")
raise Exception(str(e))
编写路由函数
在routers
目录下新建user
目录,接着在user
目录新建user.py
文件和user_schema.py
文件
- 定义注册接口的schema(
user_schema.py
)
from pydantic import BaseModel, validator, Field
class RegisterUserBody(BaseModel):
username: str = Field(..., title="用户名", description="必传")
password: str = Field(..., title="密码", description="必传")
name: str = Field(..., title="姓名", description="必传")
email: str = Field(..., title="邮箱号", description="必传")
@validator('username', 'password', 'name', 'email')
def check_field(cls, v):
if isinstance(v, str) and len(v.strip()) == 0:
raise ValueError("不能为空")
if not isinstance(v, int):
if not v:
raise ValueError("不能为空")
return v
- 路由函数实现(
user.py
)
from fastapi import APIRouter
from app.routers.user.user_schema import RegisterUserBody
from app.curd.user.UserDao import UserDao
router = APIRouter()
@router.post('/register', name='用户注册', description='用户注册')
def register(data: RegisterUserBody):
UserDao.register_user(**data.dict())
return dict(code=200, msg='注册成功')
注册路由
main.py
加入这两段代码
from app.routers.user import user
fun.include_router(user.router, prefix='/api/user', tags=["用户模块"])
测试注册功能
浏览器打开http://127.0.0.1:8080/docs#/
swagger文档
请求之后发现服务错误了
原来是数据库中不存在
data_factory_user
表,解决方法:在main.py
文件加入,重启服务即可
from app.curd.user import UserDao
from app.models import Base, engine
Base.metadata.create_all(engine)
data_factory_user
表成功创建
再测试一下~
相同的用户名再请求一下
又双出现报错了
我们下期来优化这个痛点~
用户名为空,请求一下
这也太难看了,emmmm也放到下一期优化
总结
今天内容有点多,建议大家慢慢啃下来,上面的代码还需要继续优化,我们先来总结一下有哪些优化点:
- 抛异常时,没有处理,直接服务器错误了
- schema校验不通过时,返参太难看了
- 初始化建表时,需要在
main.py
文件引入,不太方便 - 返参没有统一的格式
- 编写UserDao时,需要手动try...except```比较繁琐...
- user表的密码明文存储,不太安全
- 注册router时,需要一个个include_router,太麻烦了
- ...
好了,今天先到这里了,我们下期见哈~