feat: 初始化FastAPI项目基础框架

添加项目基础结构,包括:
- 核心模块(src/main.py)
- 路由模块(users/items)
- 数据库配置和模型
- 日志工具
- 测试用例
- 项目文档和依赖配置
This commit is contained in:
2025-12-15 11:34:24 +08:00
commit 3a5cc50d02
20 changed files with 1157 additions and 0 deletions

0
src/__init__.py Normal file
View File

0
src/db/__init__.py Normal file
View File

22
src/db/database.py Normal file
View File

@@ -0,0 +1,22 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import os
from dotenv import load_dotenv
load_dotenv()
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./test.db")
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

58
src/db/models.py Normal file
View File

@@ -0,0 +1,58 @@
"""
数据库模型模块
该模块定义了 SQLAlchemy ORM 模型,用于与数据库进行交互。
当前包含日志表的模型定义。
"""
from sqlalchemy import Column, String, Text, DateTime, BIGINT
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime
# 创建基类,所有模型都需要继承此类
Base = declarative_base()
class Log(Base):
"""
系统日志数据库模型
该模型定义了日志表的结构,用于存储系统的各种日志信息,
包括普通日志和异常日志。
"""
__tablename__ = "logs" # 数据库表名
# 日志ID主键自动递增
id = Column(BIGINT, primary_key=True, autoincrement=True, comment="日志ID主键")
# 日志时间戳默认为当前UTC时间
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, comment="日志时间戳")
# 日志级别 (INFO, WARNING, ERROR, DEBUG, CRITICAL)
level = Column(String(20), nullable=False, comment="日志级别 (INFO, WARNING, ERROR, DEBUG, CRITICAL)")
# 产生日志的模块名
module = Column(String(100), nullable=False, comment="产生日志的模块")
# 产生日志的函数名(可选)
function = Column(String(100), nullable=True, comment="产生日志的函数")
# 日志消息内容
message = Column(Text, nullable=False, comment="日志消息")
# 错误堆栈信息(可选,主要用于异常日志)
traceback = Column(Text, nullable=True, comment="错误堆栈信息")
# 请求URL可选用于记录HTTP请求相关信息
request_url = Column(String(500), nullable=True, comment="请求URL")
# 请求方法(可选,如 GET, POST 等)
request_method = Column(String(10), nullable=True, comment="请求方法 (GET, POST等)")
# 用户代理信息(可选)
user_agent = Column(String(500), nullable=True, comment="用户代理")
# IP地址可选
ip_address = Column(String(45), nullable=True, comment="IP地址")
# 关联的用户ID可选
user_id = Column(BIGINT, nullable=True, comment="关联的用户ID")

59
src/main.py Normal file
View File

@@ -0,0 +1,59 @@
"""
FastAPI 应用主入口文件
该文件负责初始化 FastAPI 应用实例,配置中间件,
注册路由以及定义根路径和健康检查端点。
"""
import sys
import os
# 将项目根目录添加到 Python 路径中,确保可以正确导入项目模块
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from src.routers import users, items
# 初始化 FastAPI 应用实例
app = FastAPI(
title="规范FastApi 开发基础框架",
description="规范的FastApi 开发基础框架",
version="1.0.0"
)
# 配置 CORS 中间件,允许所有来源、凭证、方法和头部
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
allow_origin_regex=None,
)
# 注册路由模块
# 用户相关路由,前缀为 /users标签为 users
app.include_router(users.router, prefix="/users", tags=["users"])
# 物品相关路由,前缀为 /items标签为 items
app.include_router(items.router, prefix="/items", tags=["items"])
# 根路径端点,返回欢迎信息
@app.get("/")
async def root():
return {"message": "Welcome to 规范FastApi 开发基础框架"}
# 健康检查端点,用于检查应用是否正常运行
@app.get("/health")
async def health_check():
return {"status": "healthy"}
# 当直接运行此文件时启动应用服务器
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"src.main:app",
host="0.0.0.0",
port=8000,
reload=True
)

0
src/models/__init__.py Normal file
View File

36
src/models/item.py Normal file
View File

@@ -0,0 +1,36 @@
"""
物品数据模型模块
该模块定义了物品相关的数据模型,使用 Pydantic 进行数据验证和序列化。
包括基础物品模型、创建物品模型和完整物品模型。
"""
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
class ItemBase(BaseModel):
"""
物品基础模型,定义了物品的基本信息字段
"""
name: str # 物品名称,必需字段
description: Optional[str] = None # 物品描述,可选字段
price: float # 物品价格,必需字段
class ItemCreate(ItemBase):
"""
物品创建模型,继承自 ItemBase
当前与 ItemBase 相同,但保留独立的类以便未来扩展
"""
pass
class Item(ItemBase):
"""
完整物品模型,继承自 ItemBase增加了数据库相关字段
"""
id: int # 物品唯一标识符
created_at: datetime = None # 物品创建时间,可选字段
class Config:
# 允许从 ORM 模型转换为 Pydantic 模型
from_attributes = True

35
src/models/user.py Normal file
View File

@@ -0,0 +1,35 @@
"""
用户数据模型模块
该模块定义了用户相关的数据模型,使用 Pydantic 进行数据验证和序列化。
包括基础用户模型、创建用户模型和完整用户模型。
"""
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
class UserBase(BaseModel):
"""
用户基础模型,定义了用户的基本信息字段
"""
email: str # 用户邮箱,必需字段
first_name: str # 用户名字,必需字段
last_name: str # 用户姓氏,必需字段
class UserCreate(UserBase):
"""
用户创建模型,继承自 UserBase增加了密码字段
"""
password: str # 用户密码,必需字段
class User(UserBase):
"""
完整用户模型,继承自 UserBase增加了数据库相关字段
"""
id: int # 用户唯一标识符
created_at: datetime = None # 用户创建时间,可选字段
class Config:
# 允许从 ORM 模型转换为 Pydantic 模型
from_attributes = True

0
src/routers/__init__.py Normal file
View File

123
src/routers/items.py Normal file
View File

@@ -0,0 +1,123 @@
"""
物品路由器模块
该模块定义了物品相关的 RESTful API 端点,
包括创建、读取、更新和删除物品等功能。
注意:当前实现使用内存存储,实际应用中应替换为数据库存储。
"""
import sys
import os
# 将项目根目录添加到 Python 路径中,确保可以正确导入项目模块
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from fastapi import APIRouter, HTTPException
from typing import List
from src.models.item import Item, ItemCreate
# 创建 API 路由器实例
router = APIRouter()
# 模拟数据库存储,实际应用中应使用真实数据库
items_db = []
# 创建物品端点
# 接收 ItemCreate 模型数据,返回创建的 Item 对象
@router.post("/", response_model=Item, status_code=201)
async def create_item(item: ItemCreate):
"""
创建新物品
参数:
- item: ItemCreate 模型,包含物品创建所需信息
返回:
- Item: 创建成功的物品对象
"""
# 创建新物品对象并添加到数据库
new_item = Item(id=len(items_db) + 1, **item.dict())
items_db.append(new_item)
return new_item
# 根据物品ID获取物品信息端点
@router.get("/{item_id}", response_model=Item)
async def read_item(item_id: int):
"""
根据物品ID获取物品信息
参数:
- item_id: 物品ID
返回:
- Item: 找到的物品对象
异常:
- HTTPException: 当物品不存在时返回 404 错误
"""
# 查找指定ID的物品
for item in items_db:
if item.id == item_id:
return item
raise HTTPException(status_code=404, detail="Item not found")
# 获取物品列表端点,支持分页
@router.get("/", response_model=List[Item])
async def read_items(skip: int = 0, limit: int = 100):
"""
获取物品列表,支持分页
参数:
- skip: 跳过的记录数,默认为 0
- limit: 返回的记录数,默认为 100
返回:
- List[Item]: 物品对象列表
"""
return items_db[skip : skip + limit]
# 更新物品信息端点
@router.put("/{item_id}", response_model=Item)
async def update_item(item_id: int, item_update: ItemCreate):
"""
更新物品信息
参数:
- item_id: 要更新的物品ID
- item_update: ItemCreate 模型,包含更新后的物品信息
返回:
- Item: 更新后的物品对象
异常:
- HTTPException: 当物品不存在时返回 404 错误
"""
# 查找并更新指定ID的物品
for index, item in enumerate(items_db):
if item.id == item_id:
updated_item = Item(id=item_id, **item_update.dict())
items_db[index] = updated_item
return updated_item
raise HTTPException(status_code=404, detail="Item not found")
# 删除物品端点
@router.delete("/{item_id}", status_code=204)
async def delete_item(item_id: int):
"""
删除物品
参数:
- item_id: 要删除的物品ID
返回:
- 无内容,成功时返回 204 状态码
异常:
- HTTPException: 当物品不存在时返回 404 错误
"""
# 查找并删除指定ID的物品
for index, item in enumerate(items_db):
if item.id == item_id:
items_db.pop(index)
return
raise HTTPException(status_code=404, detail="Item not found")

131
src/routers/users.py Normal file
View File

@@ -0,0 +1,131 @@
"""
用户路由器模块
该模块定义了用户相关的 RESTful API 端点,
包括创建、读取、更新和删除用户等功能。
注意:当前实现使用内存存储,实际应用中应替换为数据库存储。
"""
import sys
import os
# 将项目根目录添加到 Python 路径中,确保可以正确导入项目模块
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from fastapi import APIRouter, HTTPException
from typing import List
from src.models.user import User, UserCreate
# 创建 API 路由器实例
router = APIRouter()
# 模拟数据库存储,实际应用中应使用真实数据库
users_db = []
# 创建用户端点
# 接收 UserCreate 模型数据,返回创建的 User 对象
@router.post("/", response_model=User, status_code=201)
async def create_user(user: UserCreate):
"""
创建新用户
参数:
- user: UserCreate 模型,包含用户创建所需信息
返回:
- User: 创建成功的用户对象
异常:
- HTTPException: 当邮箱已被注册时返回 400 错误
"""
# 检查邮箱是否已存在
for existing_user in users_db:
if existing_user.email == user.email:
raise HTTPException(status_code=400, detail="Email already registered")
# 创建新用户对象并添加到数据库
new_user = User(id=len(users_db) + 1, **user.dict())
users_db.append(new_user)
return new_user
# 根据用户ID获取用户信息端点
@router.get("/{user_id}", response_model=User)
async def read_user(user_id: int):
"""
根据用户ID获取用户信息
参数:
- user_id: 用户ID
返回:
- User: 找到的用户对象
异常:
- HTTPException: 当用户不存在时返回 404 错误
"""
# 查找指定ID的用户
for user in users_db:
if user.id == user_id:
return user
raise HTTPException(status_code=404, detail="User not found")
# 获取用户列表端点,支持分页
@router.get("/", response_model=List[User])
async def read_users(skip: int = 0, limit: int = 100):
"""
获取用户列表,支持分页
参数:
- skip: 跳过的记录数,默认为 0
- limit: 返回的记录数,默认为 100
返回:
- List[User]: 用户对象列表
"""
return users_db[skip : skip + limit]
# 更新用户信息端点
@router.put("/{user_id}", response_model=User)
async def update_user(user_id: int, user_update: UserCreate):
"""
更新用户信息
参数:
- user_id: 要更新的用户ID
- user_update: UserCreate 模型,包含更新后的用户信息
返回:
- User: 更新后的用户对象
异常:
- HTTPException: 当用户不存在时返回 404 错误
"""
# 查找并更新指定ID的用户
for index, user in enumerate(users_db):
if user.id == user_id:
updated_user = User(id=user_id, **user_update.dict())
users_db[index] = updated_user
return updated_user
raise HTTPException(status_code=404, detail="User not found")
# 删除用户端点
@router.delete("/{user_id}", status_code=204)
async def delete_user(user_id: int):
"""
删除用户
参数:
- user_id: 要删除的用户ID
返回:
- 无内容,成功时返回 204 状态码
异常:
- HTTPException: 当用户不存在时返回 404 错误
"""
# 查找并删除指定ID的用户
for index, user in enumerate(users_db):
if user.id == user_id:
users_db.pop(index)
return
raise HTTPException(status_code=404, detail="User not found")

0
src/services/__init__.py Normal file
View File

0
src/utils/__init__.py Normal file
View File

179
src/utils/logger.py Normal file
View File

@@ -0,0 +1,179 @@
"""
日志工具模块
该模块提供了完整的日志记录功能,包括:
1. 控制台日志输出
2. 数据库日志存储
3. 异常信息捕获和记录
4. 不同日志级别的记录函数
日志信息会被同时输出到控制台和存储到数据库中,便于问题排查和系统监控。
"""
import sys
import os
import logging
import traceback
from typing import Optional
from datetime import datetime
# 将项目根目录添加到 Python 路径中,确保可以正确导入项目模块
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from src.db.database import get_db
from src.db.models import Log
# 配置基础日志设置
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# 创建模块级日志记录器
logger = logging.getLogger(__name__)
def log_to_database(
level: str,
message: str,
module: str,
function: Optional[str] = None,
traceback_info: Optional[str] = None,
request_url: Optional[str] = None,
request_method: Optional[str] = None,
user_agent: Optional[str] = None,
ip_address: Optional[str] = None,
user_id: Optional[int] = None
):
"""
将日志信息保存到数据库
参数:
- level: 日志级别 (INFO, WARNING, ERROR, DEBUG)
- message: 日志消息内容
- module: 产生日志的模块名
- function: 产生日志的函数名(可选)
- traceback_info: 异常堆栈信息(可选)
- request_url: 请求URL可选
- request_method: 请求方法(可选)
- user_agent: 用户代理信息(可选)
- ip_address: IP地址可选
- user_id: 用户ID可选
"""
try:
# 获取数据库会话
db_generator = get_db()
db = next(db_generator)
# 创建日志条目对象
log_entry = Log(
level=level,
message=message,
module=module,
function=function,
traceback=traceback_info,
request_url=request_url,
request_method=request_method,
user_agent=user_agent,
ip_address=ip_address,
user_id=user_id
)
# 保存到数据库
db.add(log_entry)
db.commit()
db.refresh(log_entry)
db.close()
except Exception as e:
# 如果数据库记录失败,至少打印到控制台
logger.error(f"Failed to log to database: {str(e)}")
def capture_exception(
exception: Exception,
module: str,
function: Optional[str] = None,
request_url: Optional[str] = None,
request_method: Optional[str] = None,
user_agent: Optional[str] = None,
ip_address: Optional[str] = None,
user_id: Optional[int] = None
):
"""
捕获并记录异常信息
参数:
- exception: 捕获到的异常对象
- module: 产生异常的模块名
- function: 产生异常的函数名(可选)
- request_url: 请求URL可选
- request_method: 请求方法(可选)
- user_agent: 用户代理信息(可选)
- ip_address: IP地址可选
- user_id: 用户ID可选
"""
# 获取异常堆栈信息
tb_str = ''.join(traceback.format_exception(type(exception), exception, exception.__traceback__))
# 记录错误日志到数据库和控制台
log_to_database(
level="ERROR",
message=str(exception),
module=module,
function=function,
traceback_info=tb_str,
request_url=request_url,
request_method=request_method,
user_agent=user_agent,
ip_address=ip_address,
user_id=user_id
)
# 同时打印到控制台
logger.error(f"[{module}] {str(exception)}", exc_info=True)
def info(message: str, module: str, function: Optional[str] = None):
"""
记录INFO级别日志
参数:
- message: 日志消息内容
- module: 产生日志的模块名
- function: 产生日志的函数名(可选)
"""
logger.info(f"[{module}] {message}")
log_to_database("INFO", message, module, function)
def warning(message: str, module: str, function: Optional[str] = None):
"""
记录WARNING级别日志
参数:
- message: 日志消息内容
- module: 产生日志的模块名
- function: 产生日志的函数名(可选)
"""
logger.warning(f"[{module}] {message}")
log_to_database("WARNING", message, module, function)
def error(message: str, module: str, function: Optional[str] = None):
"""
记录ERROR级别日志
参数:
- message: 日志消息内容
- module: 产生日志的模块名
- function: 产生日志的函数名(可选)
"""
logger.error(f"[{module}] {message}")
log_to_database("ERROR", message, module, function)
def debug(message: str, module: str, function: Optional[str] = None):
"""
记录DEBUG级别日志
参数:
- message: 日志消息内容
- module: 产生日志的模块名
- function: 产生日志的函数名(可选)
"""
logger.debug(f"[{module}] {message}")
log_to_database("DEBUG", message, module, function)