FastAPI框架學習筆記

目錄結構

在這裏插入圖片描述

主目錄下

database.py (創建數據庫連接)
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:[email protected]:3306/domain_name"

engine = create_engine(SQLALCHEMY_DATABASE_URL)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()
logger.py
import logging
import ctypes

FOREGROUND_WHITE = 0x0007
FOREGROUND_BLUE = 0x01  # text color contains blue.
FOREGROUND_GREEN = 0x02  # text color contains green.
FOREGROUND_RED = 0x04  # text color contains red.
FOREGROUND_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN

STD_OUTPUT_HANDLE = -11
std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)


def set_color(color, handle=std_out_handle):
    bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
    return bool


class Logger:
    def __init__(self, path='./logs/log.txt', clevel=logging.DEBUG, Flevel=logging.DEBUG):
        self.logger = logging.getLogger(path)
        self.logger.setLevel(logging.DEBUG)
        fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
        # 設置CMD日誌
        sh = logging.StreamHandler()
        sh.setFormatter(fmt)
        sh.setLevel(clevel)
        # 設置文件日誌
        fh = logging.FileHandler(path)
        fh.setFormatter(fmt)
        fh.setLevel(Flevel)
        self.logger.addHandler(sh)
        self.logger.addHandler(fh)

    def debug(self, message):
        self.logger.debug(message)

    def info(self, message):
        self.logger.info(message)

    def war(self, message, color=FOREGROUND_YELLOW):
        set_color(color)
        self.logger.warn(message)
        set_color(FOREGROUND_WHITE)

    def error(self, message, color=FOREGROUND_RED):
        set_color(color)
        self.logger.error(message)
        set_color(FOREGROUND_WHITE)

    def cri(self, message):
        self.logger.critical(message)


logger = Logger()


if __name__ == '__main__':
    logyyx = Logger('yyx.log', logging.WARNING, logging.DEBUG)
    logyyx.debug('一個debug信息')
    logyyx.info('一個info信息')
    logyyx.war('一個warning信息')
    logyyx.error('一個error信息')
    logyyx.cri('一個致命critical信息')
main.py
from fastapi import FastAPI, HTTPException, Header
from database import engine
from user import models as user_model, router as user_router


user_model.Base.metadata.create_all(bind=engine)  # 創建表

app = FastAPI()


async def get_token_header(x_token: str = Header(...)):  # 這裏可以做鑑權使用
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")


app.include_router(user_router.router,
                   prefix='/users',
                   tags=['users'],
                   # dependencies=[Depends(get_token_header)],
                   responses={404: {'description': 'Not found'}})


if __name__ == '__main__':
    import uvicorn
    uvicorn.run('main:app', reload=True, host='127.0.0.1')
setting.py
from fastapi.middleware.cors import CORSMiddleware
from main import app

origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

User應用目錄下

init.py
__all__ = ['models', 'router']
crud.py (對數據進行增刪改查的操作)
from sqlalchemy.orm import Session
from user import models, schemas
from logger import logger
from datetime import datetime, timedelta
from functools import lru_cache


@lru_cache()
def get_user(db: Session, user_id: int):
    logger.debug('一個debug信息')
    logger.info('一個info信息')
    logger.war('一個warning信息')
    logger.error('一個error信息')
    logger.cri('一個致命critical信息')
    return db.query(models.User).filter(models.User.id == user_id).first()


def update_user(db: Session, user_id: int, email: str, password: str):
    db_user = db.query(models.User).filter(models.User.id == user_id).first()
    if email is None:
        db_user.email = email
    if password is None:
        db_user.hashed_password = password
    db.commit()
    db.refresh(db_user)
    return db_user


def delete_user(db: Session, user_id: int):
    # 批量刪除
    db.query(models.User).filter(models.User.id == user_id).update({models.User.is_active: 0})
    db.commit()
    return {'status': 'delete success'}


def get_user_by_eamil(db: Session, email: str, query_time: datetime):
    # 模糊查詢/查詢修改時間在一天之前的數據
    if email:
        return db.query(models.User).filter(models.User.email.like(email + '%')).all()
    if query_time:
        return db.query(models.User).filter(models.User.update_time < query_time - timedelta(days=1), models.User.is_active == 1).all()


def batch_update_user(db: Session, update_time: datetime):
    # 根據修改時間批量更新, 類似將手動取消的所有域名恢復狀態
    if update_time:
        db.query(models.User).filter(models.User.update_time > update_time).update({models.User.is_active: 1})
        db.commit()
        return db.query(models.User).filter(models.User.update_time > update_time).all()


def get_users(db: Session, skip: int = 0, limit: int = 100):
    # 分頁查詢
    return db.query(models.User).offset(skip).limit(limit).all()

 
def create_user(db: Session, user: schemas.UserCreate):
    fake_hashed_password = user.password + 'notreallyhashed'
    db_user = models.User(email=user.email, hashed_password=fake_hashed_password, info=user.info)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user


def get_items(db: Session, skip: int = 0, limit: int = 100):
    return db.query(models.Item).offset(skip).limit(limit).all()


def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int):
    db_item = models.Item(**item.dict(), owner_id=user_id)
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    return db_item

models.py (數據模型,建表使用)
from database import Base
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, TIMESTAMP, text, JSON
from sqlalchemy.orm import relationship


class User(Base):
    __tablename__ = 'users_test'

    id = Column(Integer, primary_key=True, index=True)
    email = Column(String(50), unique=True, index=True)
    hashed_password = Column(String(50))
    update_time = Column(TIMESTAMP(timezone=False), nullable=False)
    create_time = Column(TIMESTAMP(timezone=False), nullable=False, server_default=text('NOW()'))
    is_active = Column(Boolean, default=True)
    info = Column(JSON, nullable=True)

    items = relationship('Item', back_populates='owner')


class Item(Base):
    __tablename__ = 'items_test'

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(50), index=True)
    description = Column(String(50), index=True)
    owner_id = Column(Integer, ForeignKey('users_test.id'))

    owner = relationship('User', back_populates='items')
router.py (接口uri)
from fastapi import Depends, HTTPException, APIRouter, Body
from typing import List
from sqlalchemy.orm import Session
from datetime import datetime
from logger import logger
from user import crud, schemas
from database import SessionLocal

router = APIRouter()


def get_db():  # 在每個請求之前建立數據庫連接,請求之後關閉連接,再建立一個新連接
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


@router.post('/', response_model=schemas.User, tags=['users'])
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    """
    添加用戶接口
    \f
    :param user:
    :param db:
    :return:
    """
    db_user = crud.get_user_by_eamil(db, email=user.email, query_time=datetime.now())
    if db_user:
        raise HTTPException(status_code=400, detail='email already registered')
    return crud.create_user(db=db, user=user)


@router.get('/', response_model=List[schemas.User], tags=['users'])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    users = crud.get_users(db, skip=skip, limit=limit)
    return users


@router.get('/email', response_model=List[schemas.User], tags=['users'])
def read_user_by_email(email: str = None, update_time: datetime = None, db: Session = Depends(get_db)):
    # 獲取更改時間超過一天的/通過email模糊查詢
    users = crud.get_user_by_eamil(db, email, update_time)
    return users


@router.put('/update', response_model=List[schemas.User], tags=['users'])
def batch_update_user_info(update_time: datetime = None, db: Session = Depends(get_db)):
    # 根據修改時間,批量更新(類似將手動取消的域名狀態全部設置成可用)
    users = crud.batch_update_user(db, update_time)
    return users


@router.get('/{user_id}', response_model=schemas.User, tags=['users'])
def read_users(user_id: int, db: Session = Depends(get_db)):
    logger.debug('user一個debug信息')
    logger.info('user一個info信息')
    logger.war('user一個warning信息')
    logger.error('user一個error信息')
    logger.cri('user一個致命critical信息')
    db_user = crud.get_user(db, user_id=user_id)
    if db_user is None:
        raise HTTPException(status_code=404, detail='User not found')
    return db_user


@router.put('/{user_id}', tags=['users'])
def update_users(user_id: int, email: str = Body(...), password: str = Body(None), db: Session = Depends(get_db)):
    db_user = crud.get_user(db, user_id=user_id)
    if db_user is None:
        raise HTTPException(status_code=404, detail='User not found')
    db_user = crud.update_user(db, user_id=user_id, email=email, password=password)
    return db_user


@router.delete('/{user_id}', tags=['users'])
def delete_users(user_id: int, db: Session = Depends(get_db)):
    db_user = crud.get_user(db, user_id=user_id)
    if db_user is None:
        raise HTTPException(status_code=404, detail='User not found')
    db_user = crud.delete_user(db, user_id=user_id)
    return db_user
schemas.py (接口調用傳參、返回的模型)
from pydantic import BaseModel, Json
from typing import List


class ItemBase(BaseModel):
    title: str
    description: str = None


class ItemCreate(ItemBase):
    pass


class Item(ItemBase):
    id: int
    owner_id: int

    class Config:   # https://pydantic-docs.helpmanual.io/usage/model_config/
        orm_mode = True   # 是否允許使用orm模式  沒有orm_mode,如果您從路徑操作返回了SQLAlchemy模型,則該模型將不包含關係數據。


class UserBase(BaseModel):
    email: str


class UserCreate(UserBase):
    password: str
    info: dict


class User(UserBase):
    id: int
    is_active: bool
    info: dict   # 字典就是json格式
    items: List[Item] = []

    class Config:
        orm_mode = True
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章