fastapi_No.17_多文件系统

组成部分

在实际项目中,往往会有多个接口,在我们实际开发过程中,通常会根据各个功能模块,将开发的各个部分分别存放在不同的文件夹下。本案例中通过图书管理系统,来演示这部分内容。由于代码量的问题,这里仅演示登录和图书展示两个界面相关的代码。
整体布局如下图:
在这里插入图片描述

系统配置(configs)

系统配置中主要用来存放一些资源配置的代码,例如数据库连接或者生成token的配置信息。

#configs.db.py
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base

# 数据库相关的系统配置项
DBURL = 'mysql+pymysql://root:123456@127.0.0.1:3306/libraryDB'
ENGINE = create_engine(DBURL)
Base = declarative_base(bind=ENGINE)
from passlib.context import CryptContext

SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

CONTEXT = CryptContext(schemes=['bcrypt'], deprecated="auto")

通用工具(utils)

用来存放一些系统中常用的工具函数,生成token,或者依赖函数。

#utils.db.py
from sqlalchemy.orm import Session

from configs.db import ENGINE

def get_db():
    db = Session(ENGINE)
    try:
        yield  db
    finally:
        db.close()
#utils.token.py
from jose import JWTError,jwt
from typing import Union
from datetime import timedelta,datetime

from configs.token import CONTEXT,SECRET_KEY,ALGORITHM

def hash_pwd(pwd:str) -> str:
    return CONTEXT.hash(pwd)

def verify_pwd(p_pwd:str,h_pwd:str) -> bool:
    return CONTEXT.verify(p_pwd,h_pwd)

def create_token(data:dict,expires_delta:Union[timedelta,None]=None) -> str:
    to_encode = data.copy()
    # 追加过期时间
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    # 注意此处的to_encode中的键,解token后也通过这些键来取值!
    # 利用密钥和加密算法生成token
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

数据表模型(models)

用来存放应用中用到的不同的数据表模型。

#models.user.py
from sqlalchemy import Table,Column,String,Integer,DateTime
from sqlalchemy.orm import mapper

from configs.db import Base

user_table = Table(
    "user",
    Base.metadata,
    Column("id", Integer, primary_key=True, autoincrement=True),
    Column("username", String(20),comment="用户名"),
    Column("hash_pwd", String(200),comment="加密后的密码"),
    Column("token", String(255),comment="token"),
    Column("last_time", DateTime(),comment="最后登录时间"),
    comment = "用户表"
)
# 新的一种混合方式创建数据表模型类
class User(object):
    def __init__(self,**kwargs):
        for i in kwargs:
            self.__dict__[i] = kwargs.get(i)
mapper(User,user_table)
#models.book.py
from sqlalchemy import Table,Column,String,Integer,DateTime
from sqlalchemy.orm import mapper

from configs.db import Base
book_table = Table(
    "book",
    Base.metadata,
    Column("id", Integer, primary_key=True, autoincrement=True),
    Column("title", String(50),comment="书名"),
    Column("author", Integer,comment="作者,作者表的id"),
    Column("publisher", Integer, comment="出版社,出版社表的id"),
    Column("code", String(20), comment="ISBN码"),
    comment = "图书表"
)
# 新的一种混合方式创建数据表模型类
class Book(object):
    def __init__(self,**kwargs):
        for i in kwargs:
            self.__dict__[i] = kwargs.get(i)
mapper(Book,book_table)

数据逻辑(services)

存放各个数据库表对应的增删改查的逻辑函数。

#services.user.py
from sqlalchemy.orm import Session
from datetime import datetime
from typing import Union

from models.user import User
from schemas.user import UserIn

def insert_user(db:Session,username:str,hash_pwd:str):
    token = ''
    last_time = datetime.utcnow()
    user = User(username=username,hash_pwd=hash_pwd,token=token,last_time=last_time)
    db.add(user)
    db.commit()
    return True

def update_user(db:Session,id:int,token:Union[str,None]=None,last_time:Union[datetime,None]=None):
    if token:
        db.query(User).filter(User.id == id).update({"token":token})
    if last_time:
        db.query(User).filter(User.id == id).update({"last_time":last_time})
    db.commit()
    return True

def read_user(db:Session, username:str) -> UserIn:
    user = db.query(User).filter(User.username == username).one()
    if user:
        return UserIn(**user.dict())
#services.book.py
from sqlalchemy.orm import Session
from datetime import datetime
from typing import Union

from models.book import Book
from schemas.book import BookIn

def insert_book(db:Session,book:BookIn):
    book = Book(title=book.title,author=book.author,publisher=book.publisher,code=book.code)
    db.add(book)
    db.commit()
    return True

def read_books(db:Session) -> list:
    books = db.query(Book).all()
    if books:
        result = []
        for book in books:
            result.append({
                "id":book.id,
                "title":book.title,
                "author":book.author,
                "publisher":book.publisher,
                "code":book.code
            })
        return result

数据验证模型(schemas)

根据services里面的参数,可以提炼出数据验证模型。

#services.user.py
from pydantic import BaseModel
from typing import Union
from datetime import datetime

class UserIn(BaseModel):
    username:str
    pwd:str
class UserUp(BaseModel):
    id:int
    token:Union[str,None]=None
    last_time:Union[datetime,None]=None
#services.book.py
from pydantic import BaseModel

class BookIn(BaseModel):
    title:str
    author:int
    publisher:int
    code:str

子路由(routers)

子路由是APIRouter类的实例对象,使用与FastAPI类似。用来存放各个功能模块的接口。

#routers.user.py
from fastapi import APIRouter,Depends

from sqlalchemy.orm import Session
from schemas.user import UserIn,UserUp
from utils.db import get_db
from utils.token import hash_pwd
from services.user import insert_user,update_user

user = APIRouter()

@user.post("/")
def add_user(user:UserIn,db:Session=Depends(get_db)):
    h_pwd = hash_pwd(user.pwd)
    insert_user(db=db,username=user.username,hash_pwd=h_pwd)
    return {
        "code":"0000",
        "msg":"OK"
    }

@user.put("/")
def modify_user(user:UserUp,db:Session=Depends(get_db)):
    update_user(db=db,token=user.token,last_time=user.last_time,id=user.id)
    return {
        "code": "0000",
        "msg": "OK"
    }
#routers.book.py
from fastapi import APIRouter,Depends
from sqlalchemy.orm import Session
from services.book import insert_book,read_books
from schemas.book import BookIn
from utils.db import get_db

book = APIRouter()

@book.post("/")
def add_book(book:BookIn,db:Session=Depends(get_db)):
    insert_book(db=db,book=book)
    return {
        "code":"0000",
        "msg":"OK"
    }

@book.get("/")
def get_books(db:Session=Depends(get_db)):
    data = read_books(db=db)
    return {
        "code": "0000",
        "msg": "OK",
        "data": data
    }

总路由(main)

汇总所有的子路由到一个总的路由中。

#main.py
from fastapi import FastAPI
from routers.user import user
from routers.book import book

from configs.db import Base

app = FastAPI()
#启动时,初始化创建数据库表
@app.on_event("startup")
def initdb():
    Base.metadata.create_all()
#prefix定义该子路由的路径前缀
app.include_router(user,prefix="/user",tags=["用户相关"])
app.include_router(book,prefix="/book",tags=["图书相关"])

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app="main:app",host="127.0.0.1",port=8080,reload=True)

接口呈现界面:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习_程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值