【FastAPI】使用 FastAPI 和 SQLAlchemy 记录数据库操作日志:基于装饰器的实现
在后端开发中,记录用户对数据库的操作日志(如增、删、改)不仅是调试和监控的有效工具,还能提升系统的可维护性和安全性。本文将介绍如何在 FastAPI 中使用装饰器来记录数据库操作日志,并保留修改前和修改后的内容。
一、为什么需要操作日志?
- 审计:操作日志能够追踪谁在何时对数据进行了哪些修改,尤其在处理敏感数据时非常有必要。
- 调试:当系统出现问题时,通过日志可以快速查明问题根源,尤其是在涉及数据一致性的问题时。
- 安全:可以识别恶意操作或非授权修改,从而采取相应的安全措施。
通过记录操作前后的数据状态,我们能够清楚地知道数据库的变化,并且可以在系统出错或需要回滚时进行详细分析。
二、项目设置
1. 数据库设置
首先,我们创建一个日志记录表,用于保存用户操作的详细信息。我们将使用 PostgreSQL 来存储数据(当然,你可以使用任何你熟悉的数据库系统)。
CREATE TABLE operation_logs (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL, -- 操作用户的ID
operation_type VARCHAR(50) NOT NULL, -- 操作类型,INSERT, UPDATE, DELETE
table_name VARCHAR(100) NOT NULL, -- 操作的表名
record_id INTEGER NOT NULL, -- 被操作记录的ID
operation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 操作时间
before_change TEXT, -- 修改前的数据
after_change TEXT -- 修改后的数据
);
2. 使用 SQLAlchemy 进行数据库操作
为了更好地与数据库交互,我们使用 SQLAlchemy 作为 ORM。这里是基本的 FastAPI 与 SQLAlchemy 的配置:
from fastapi import FastAPI, Depends
from sqlalchemy import create_engine, Table, MetaData
from sqlalchemy.orm import sessionmaker
app = FastAPI()
# 数据库连接配置
DATABASE_URL = "postgresql://user:password@localhost/dbname"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 获取数据库会话
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
3. 编写日志记录装饰器
装饰器是一种非常简洁且优雅的方式,可以将日志记录与业务逻辑分离。接下来,我们将创建一个装饰器,专门用于记录数据库增删改操作时的日志信息。
from functools import wraps
from datetime import datetime
import json
def log_changes(operation_type):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
db = kwargs.get('db') # 获取数据库会话
user_id = kwargs.get('user_id') # 获取用户ID
table_name = kwargs.get('table_name') # 操作的表名
record_id = kwargs.get('record_id') # 操作记录的ID
# 获取修改前的数据
before_change = func.__name__ == "delete_item" and "N/A" or db.query(Table(table_name)).filter_by(id=record_id).first()
before_change_data = json.dumps(dict(before_change)) if before_change else "N/A"
result = func(*args, **kwargs) # 执行实际的增删改操作
# 获取修改后的数据
after_change = func.__name__ == "delete_item" and "N/A" or db.query(Table(table_name)).filter_by(id=record_id).first()
after_change_data = json.dumps(dict(after_change)) if after_change else "N/A"
# 记录操作日志
log_operation(db, user_id, operation_type, table_name, record_id, before_change_data, after_change_data)
return result
return wrapper
return decorator
4. 日志记录函数
我们还需要编写一个 log_operation
函数,用来将日志信息插入到数据库中。
def log_operation(db, user_id, operation_type, table_name, record_id, before_change, after_change):
query = f"""
INSERT INTO operation_logs (user_id, operation_type, table_name, record_id, operation_time, before_change, after_change)
VALUES ({user_id}, '{operation_type}', '{table_name}', {record_id}, '{datetime.now()}', '{before_change}', '{after_change}');
"""
db.execute(query)
db.commit()
5. 应用装饰器
现在我们可以将装饰器应用到 FastAPI 的路由中,以便在用户执行增删改操作时自动记录操作日志。
@app.post("/items/")
@log_changes("INSERT")
def create_item(item: dict, user_id: int, db: SessionLocal = Depends(get_db)):
# 执行插入操作
table_name = "items"
record_id = 123 # 插入记录后生成的ID
# 实际插入代码 (示例)
db.execute(f"INSERT INTO {table_name} (name, value) VALUES ('{item['name']}', '{item['value']}')")
db.commit()
return {"status": "success", "record_id": record_id}
@app.put("/items/{item_id}")
@log_changes("UPDATE")
def update_item(item_id: int, updated_item: dict, user_id: int, db: SessionLocal = Depends(get_db)):
# 执行更新操作
table_name = "items"
# 实际更新代码 (示例)
db.execute(f"UPDATE {table_name} SET name = '{updated_item['name']}', value = '{updated_item['value']}' WHERE id = {item_id}")
db.commit()
return {"status": "updated", "item_id": item_id}
@app.delete("/items/{item_id}")
@log_changes("DELETE")
def delete_item(item_id: int, user_id: int, db: SessionLocal = Depends(get_db)):
# 执行删除操作
table_name = "items"
# 实际删除代码 (示例)
db.execute(f"DELETE FROM {table_name} WHERE id = {item_id}")
db.commit()
return {"status": "deleted", "item_id": item_id}
三、总结
通过本文的示例,我们展示了如何在 FastAPI 中结合 SQLAlchemy 使用装饰器来记录数据库的增删改操作日志。这种方法的优势在于它与业务逻辑分离,使用简单且易于扩展。此外,日志表中保存了修改前后的数据,使得系统在调试和审计时更加高效和透明。
希望这篇文章能帮助你在项目中实现类似的功能!如果你有任何问题或建议,欢迎在评论区留言。
原文地址:https://blog.csdn.net/h1773655323/article/details/142263006
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!