当前位置:首页>python>python之fastAPI实战篇(2)

python之fastAPI实战篇(2)

  • 2026-09-10 12:09:48
python之fastAPI实战篇(2)

python之fastAPI实战篇(2)

今天讲一下用户注册,登录,获取个人信息,更新个人信息和密码的功能

上一讲讲了新闻信息的接口,这一章讲用户注册登录

1.注册

流程:

前置,准备数据模型

class UserRequest(BaseModel):    username:str    password:str@router.post("/register")async def register(userdata:UserRequest, db:AsyncSession=Depends(getdatabase)):

1.先判断数据库中是否存在(通过username进行查询)

 user=await db.execute( Select(User).where(User.username == username))print(user)    result=user.scalar_one_or_none()if result:        raise HTTPException(status_code=500, detail="用户已存在")

2.对密码进行加密

先下载插件passlib[bcrypt]==1.7.4,"bcrypt==4.0.1"

pip install "passlib[bcrypt]==1.7.4"pip install "bcrypt==4.0.1"

然后进行加密

 pwd_context=CryptContext(schemes=["bcrypt"],deprecated="auto")    userdata.password=pwd_context.hash(userdata.password)

3.新增进数据库

adduser=User(**userdata.__dict__)    db.add(adduser)     await db.commit()

4.生成token,因为注册后直接登录,所以我们这里把token保存到数据库表里面

    userresult=await  db.execute(Select(User).where(User.username == username))    results=userresult.scalar_one_or_none()    token=str( uuid.uuid4())    expires_at = datetime.now() + timedelta(days=7)    userTokenadd = UserToken(user_id=results.id, token=token, expires_at=expires_at)    db.add(userTokenadd)    await db.commit()return {"msg": "注册成功", "data": {"token":token,"userInfo":{"id":results.id,"username": results.username,"bio": results.bio,"avatar": results.avatar,        }    }, "code": 200}

到这里注册功能就完成了。

2.登录

1.先判断用户名是否存在

@router.post("/login")async def login(userdata:UserRequest, db:AsyncSession=Depends(getdatabase)):    username=userdata.username    password=userdata.password    userSelect=Select(User).where(User.username == username)    user=await db.execute(userSelect)    userResult=user.scalar_one_or_none()if userResult == None:        raise HTTPException(status_code=500, detail="用户不存在")

2.用verify方法对密码进行比对

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")    pwdpassword = pwd_context.verify(password,userResult.password)if pwdpassword==False:        raise HTTPException(status_code=500, detail="密码错误")

3.生成token,如果token存在则修改,不存在则新增

 token = str(uuid.uuid4())    expires_at = datetime.now() + timedelta(days=7)    usertokenSelect=Select(UserToken).where(UserToken.user_id == userResult.id)    usertoken=await db.execute(usertokenSelect)    usertokenResult=usertoken.scalar_one_or_none()if usertokenResult:        usertokenResult.token=token        usertokenResult.expires_at =expires_atelse:        userTokenadd=UserToken(user_id=userResult.id,token=token,expires_at=expires_at)        db.add(userTokenadd)        await db.commit()return {"msg": "登录成功", "data": {"token": token,"userInfo": {"id": userResult.id,"username": userResult.username,"bio": userResult.bio,"avatar": userResult.avatar,        }    }, "code": 200}

登录到这里就完成了

3.个人信息

流程:1.获取token

@router.get("/info")async def info(authorazation:str=Header(..., alias="Authorization"), db:AsyncSession=Depends(getdatabase)):

2.判断token是否在数据库表或者是否已过期

userTokenSelect=Select(UserToken).where(UserToken.token == authorazation)    userTokendb=await db.execute(userTokenSelect)    userTokenResult=userTokendb.scalar_one_or_none()if userTokenResult == None or userTokenResult.expires_at<datetime.now():        raise HTTPException(status_code = 500,detail="用户信息不存在")

3.通过从usertoken查到的userId进入user表里面去查

    userSelect=Select(User).where(User.id==userTokenResult.user_id)    userdb=await db.execute(userSelect)    userResult=userdb.scalar_one_or_none()return {"msg": "获取个人信息成功", "data": userResult, "code": 200}

4.修改个人信息

流程大体和获取个人信息一样,不再赘述

@router.put("/update")async def update(biodata:bioRequest,authorazation:str=Header(..., alias="Authorization"), db:AsyncSession=Depends(getdatabase)):    userTokenSelect = Select(UserToken).where(UserToken.token == authorazation)    userTokendb = await db.execute(userTokenSelect)    userTokenResult = userTokendb.scalar_one_or_none()if userTokenResult == None or userTokenResult.expire_at<datetime.now():        raise HTTPException(code=500, detail="用户信息不存在")print(userTokenResult)    userSelect = Select(User).where(User.id == userTokenResult.user_id)    userdb = await db.execute(userSelect)    userResult = userdb.scalar_one_or_none()print(userResult.id)print(biodata.bio)    userResult.bio=biodata.bio    await db.commit()return {"msg": "更新个人信息成功", "data": {}, "code": 200}

5.更新密码

流程大体和更新个人信息一样,不再赘述

@router.put("/password")async def update(password:passwordUpdateRequest,authorazation:str=Header(..., alias="Authorization"), db:AsyncSession=Depends(getdatabase)):    userTokenSelect = Select(UserToken).where(UserToken.token == authorazation)    userTokendb = await db.execute(userTokenSelect)    userTokenResult = userTokendb.scalar_one_or_none()if userTokenResult == None or userTokenResult.expire_at<datetime.now():        raise HTTPException(status_code=500, detail="用户信息不存在")print(userTokenResult)    userSelect = Select(User).where(User.id == userTokenResult.user_id)    userdb = await db.execute(userSelect)    userResult = userdb.scalar_one_or_none()print(userResult.id)    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")    pwdpassword = pwd_context.verify(password.oldPassword, userResult.password)if pwdpassword == False:        raise HTTPException(status_code=500, detail="用户旧密码错误")    userResult.password=pwd_context.hash(password.newPassword)    await db.commit()return {"msg": "修改密码成功", "data": {}, "code": 200}

最后呢,写一个全局异常处理

1.先定义异常类

import tracebackfrom fastapi import HTTPException, Requestfrom fastapi.responses import JSONResponsefrom sqlalchemy.exc import IntegrityError, SQLAlchemyErrorfrom starlette import status# 开发模式:返回详细错误信息# 生产模式:返回简化错误信息DEBUG_MODE = True  # 教学项目保持开启async def http_exception_handler(request: Request, exc: HTTPException):"""    处理 HTTPException 异常    """# HTTPException 通常是业务逻辑主动抛出的,data 保持 Nonereturn JSONResponse(        status_code=exc.status_code,        content={"code": exc.status_code,"message": exc.detail,"data": None        }    )async def integrity_error_handler(request: Request, exc: IntegrityError):"""    处理数据库完整性约束错误    """    error_msg = str(exc.orig)# 判断具体的约束错误类型if"username_UNIQUE"in error_msg or "Duplicate entry"in error_msg:        detail = "用户名已存在"elif"FOREIGN KEY"in error_msg:        detail = "关联数据不存在"else:        detail = "数据约束冲突,请检查输入"# 开发模式下返回详细错误信息    error_data = Noneif DEBUG_MODE:        error_data = {"error_type": "IntegrityError","error_detail": error_msg,"path": str(request.url)        }return JSONResponse(        status_code=status.HTTP_400_BAD_REQUEST,        content={"code": 400,"message": detail,"data": error_data        }    )async def sqlalchemy_error_handler(request: Request, exc: SQLAlchemyError):"""    处理 SQLAlchemy 数据库错误    """# 开发模式下返回详细错误信息    error_data = Noneif DEBUG_MODE:        error_data = {"error_type": type(exc).__name__,"error_detail": str(exc),# 格式化异常信息为字符串,方便日志记录和调试"traceback": traceback.format_exc(),"path": str(request.url)        }return JSONResponse(        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,        content={"code": 500,"message": "数据库操作失败,请稍后重试","data": error_data        }    )async def general_exception_handler(request: Request, exc: Exception):"""    处理所有未捕获的异常    """# 开发模式下返回详细错误信息    error_data = Noneif DEBUG_MODE:        error_data = {"error_type": type(exc).__name__,"error_detail": str(exc),# 格式化异常信息为字符串,方便日志记录和调试"traceback": traceback.format_exc(),"path": str(request.url)        }return JSONResponse(        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,        content={"code": 500,"message": "服务器内部错误","data": error_data        }    )

2.注册全局异常

from fastapi import HTTPExceptionfrom sqlalchemy.exc import IntegrityError, SQLAlchemyErrorfrom utils.exception import http_exception_handler, integrity_error_handler, sqlalchemy_error_handler, \    general_exception_handlerdef register_exception_handlers(app):"""    注册全局异常处理:子类在前,父类在后;具体在前,抽象在后    """    app.add_exception_handler(HTTPException, http_exception_handler)  # 业务    app.add_exception_handler(IntegrityError, integrity_error_handler)  # 数据完整性约束    app.add_exception_handler(SQLAlchemyError, sqlalchemy_error_handler)  # 数据库    app.add_exception_handler(Exception, general_exception_handler)  # 兜底

3.main.py引入

from utils.exception_handlers import register_exception_handlers# 注册异常处理器register_exception_handlers(app)

下一讲更好玩,大家敬请期待

需要了解服务器和域名的购买以及返佣政策的可以找我,我有朋友做这方面对这些比较了解。
需要源码联系
需要源码可以加群,第一个是微信群,第二个是QQ群
微信群
第一个群:只讨论java+vue的项目,学历提升和卖服务器的就别进了,进了也会被踢。
第二个群:只讨论python项目,以后python的代码和教程会在群里开源,学历提升和卖服务器的就别进了,进了也会被踢。
QQ群

最新文章

随机文章