FastAPI-Scaff脚手架项目完整配置指南

问题背景

使用fastapi-scaff脚手架创建项目后,发现三个常见问题:

  1. 时区配置缺失 默认的时区对于linux mac相对友好 对于Windows会有问题 (其实新增环境变量TZ也可以解决 不过本文会创建新的工具类 担心有其他问题)
    TZ环境变量 ✅ 默认设置 ❌ 通常为空 Windows不自动设置
    zoneinfo数据 ✅ /usr/share/zoneinfo ❌ 需要tzdata包 Python标准库路径不同
    Python zoneinfo模块 ✅ 自动使用系统数据 ❌ 需要tzdata包 Windows下fallback机制
    因为:默认脚手架的user模型类创建的时候 引用的是 toollib.utils.now2timestamp,而不是用zoneinfo
    主要是三个地方
bash 复制代码
$ echo $TZ
空(但系统有时区配置)

$ ls /usr/share/zoneinfo/Asia/Shanghai
✅ 文件存在

$ python3 -c "import zoneinfo; print(zoneinfo.ZoneInfo('Asia/Shanghai'))"
✅ 正常输出
  1. ORM alembic 如果使用Base类不一致 统一使用 DeclBase
  2. 完善 alembic 配置文件 env.py

完整解决方案

第一步:创建项目

bash 复制代码
# 1. 安装脚手架
pip install fastapi-scaff==0.5.7

# 2. 创建项目
fastapi-scaff new my_fastapi 

# 3. 进入项目目录
cd my_fastapi

fastapi-scaff 常见参数 -h可以直接看

bash 复制代码
 
  -e, --edition   `new`时可指定项目结构版本(默认标准版)  这个用的多一些
  -d, --db        `new`时可指定项目数据库(默认sqlite)
  -v, --vn        `add`时可指定版本(默认v1)
  -s, --subdir    `add`时可指定子目录(默认空)
  -t, --target    `add`时可指定目标(默认asm)
  --celery        `new`|`add`时可指定是否集成celery(默认不集成)

examples: 
  `new`: fastapi-scaff new <myproj>
  `add`: fastapi-scaff add <myapi>

第二步:添加缺失依赖

bash 复制代码
# 添加时区和迁移工具依赖
echo "tzdata>=2021.5" >> requirements.txt
echo "alembic>=1.11.0" >> requirements.txt

# 安装所有依赖
pip install -r requirements.txt

第三步:创建时区工具文件

bash 复制代码
# 创建统一时区工具
cat > app/utils/mytime.py << 'EOF'
from datetime import datetime
from zoneinfo import ZoneInfo

SHANGHAI_TZ = ZoneInfo("Asia/Shanghai")

def now() -> datetime:
    """返回上海时区的当前时间"""
    return datetime.now(SHANGHAI_TZ)

def now_timestamp() -> int:
    """返回当前时间戳(秒)"""
    return int(now().timestamp())

def now_ms() -> int:
    """返回当前时间戳(毫秒)"""
    return int(now().timestamp() * 1000)
EOF

第四步:修改用户模型

bash 复制代码
# 备份原文件
cp app/models/user.py app/models/user.py.backup

# 使用sed修改文件
sed -i '/from toollib.utils import now2timestamp/d' app/models/user.py
sed -i '/from app.initializer import g/a\from app.utils import mytime' app/models/user.py
sed -i 's/default=now2timestamp/default=mytime.now_timestamp/g' app/models/user.py

修改后的关键部分:

python 复制代码
from sqlalchemy import Column, BigInteger, Integer, String
from app.initializer import g
from app.models import DeclBase
from app.utils import mytime  # 新增导入

class User(DeclBase):
    __tablename__ = "user"
    # ... 其他字段保持不变
    created_at = Column(BigInteger, default=mytime.now_timestamp, comment="创建时间")
    updated_at = Column(BigInteger, default=mytime.now_timestamp, onupdate=mytime.now_timestamp, comment="更新时间")

第五步:初始化Alembic迁移

bash 复制代码
# 初始化Alembic
alembic init alembic

# 配置env.py使用项目Base类
cat >> alembic/env.py << 'EOF'

# 添加项目路径
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))

# 导入Base类
from app.models import DeclBase
target_metadata = DeclBase.metadata

# 设置数据库URL(根据配置文件)
config.set_main_option("sqlalchemy.url", "sqlite:///app_dev.sqlite")
EOF

使用sqlite的完整env.py配置文件:

python 复制代码
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
import os
import sys

config = context.config

# Set database URL directly
config.set_main_option("sqlalchemy.url", "sqlite:///app_dev.sqlite")

# Add project root to Python path
project_root = os.path.dirname(os.path.dirname(__file__))
sys.path.append(project_root)

# Import Base class
try:
    from app.models import DeclBase
    target_metadata = DeclBase.metadata
except ImportError:
    try:
        from app.initializer._db import DeclBase
        target_metadata = DeclBase.metadata
    except ImportError:
        from sqlalchemy.ext.declarative import declarative_base
        DeclBase = declarative_base()
        target_metadata = DeclBase.metadata

if config.config_file_name is not None:
    fileConfig(config.config_file_name)

def run_migrations_offline():
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )
    with context.begin_transaction():
        context.run_migrations()

def run_migrations_online():
    connectable = engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )
    with connectable.connect() as connection:
        context.configure(
            connection=connection, target_metadata=target_metadata
        )
        with context.begin_transaction():
            context.run_migrations()

if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()

第六步:执行数据库迁移

bash 复制代码
# 生成迁移文件
alembic revision --autogenerate -m "init"

# 应用迁移
alembic upgrade head

# 验证表结构
sqlite3 app_dev.sqlite ".tables"

API测试流程

1. 启动服务

bash 复制代码
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

2. 创建用户

bash 复制代码
curl -X POST "http://127.0.0.1:8000/api/v1/user" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "13634759152",
    "password": "passwd",
    "name": "admin",
    "age": 0,
    "gender": 1
  }'

3. 登录获取Token

bash 复制代码
curl -X POST "http://127.0.0.1:8000/api/v1/user/login" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "13634759152",
    "password": "passwd"
  }'

4. 使用Token查询用户

bash 复制代码
# 使用上一步返回的token
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjIwMDA5MDc1NjI2MjY1ODg2NzIiLCJwaG9uZSI6IjEzNjM0NzU5MTUyIiwibmFtZSI6ImFkbWluIiwiYWdlIjowLCJnZW5kZXIiOjEsImV4cCI6MTc2ODQ4MTIyOX0.yS_pyuHfR0FuctSsb86zebYVlk8CFK2-ErsQMBvRqaA"

curl -X GET "http://127.0.0.1:8000/api/v1/user/2000907562626588672" \
  -H "accept: application/json" \
  -H "Authorization: Bearer $TOKEN"

5. 查询用户列表

bash 复制代码
curl -X GET "http://127.0.0.1:8000/api/v1/user?page=1&size=10" \
  -H "accept: application/json" \
  -H "Authorization: Bearer $TOKEN"

验证命令

bash 复制代码
# 验证时区配置
python -c "from app.utils.mytime import now_timestamp; print('当前时间戳:', now_timestamp())"

# 验证数据库迁移
alembic current

# 验证表结构
sqlite3 app_dev.sqlite "SELECT name FROM sqlite_master WHERE type='table';"

问题排查清单

问题 检查命令 解决方案
时区错误 python -c "from zoneinfo import ZoneInfo; print(ZoneInfo('Asia/Shanghai'))" pip install tzdata
Alembic找不到Base grep -r "DeclBase" app/ 修改env.py导入路径
迁移文件不生成 sqlite3 app_dev.sqlite ".tables" 检查env.py中的target_metadata
Token认证失败 检查用户表的jwt_key字段 确保jwt_key不为空

总结

fastapi-scaff脚手架创建的项目需要手动补充三个核心配置:

  1. 时区统一 :创建app/utils/mytime.py,替换所有时间相关函数
  2. 数据库迁移:初始化Alembic,配置正确的Base类和数据库连接
  3. 模型一致:确保所有模型继承同一个Base类

完成上述配置后,项目即可正常运行完整的JWT认证流程和数据库迁移功能。

欢迎焦虑 沟通 有错误 指正留言~

相关推荐
Hi_kenyon5 小时前
FastAPI+VUE3创建一个项目的步骤模板(三)
python·fastapi
Hi_kenyon8 小时前
FastAPI+VUE3创建一个项目的步骤模板(一)
python·fastapi
计算衎1 天前
FastAPI后端和VUE前端的数据交互原理详解
前端·vue.js·fastapi
IMPYLH1 天前
Lua 的 Debug(调试) 模块
开发语言·笔记·python·单元测试·lua·fastapi
@我本楚狂人1 天前
Python MCP实战:构建 FastAPI 服务端与客户端示例&MCP客户端调用
开发语言·python·fastapi
绝不收费—免费看不了了联系我2 天前
Fastapi的单进程响应问题 和 解决方法
开发语言·后端·python·fastapi
Non-existent9872 天前
Flutter + FastAPI 30天速成计划自用并实践-第10天-组件化开发实践
android·flutter·fastapi
闲人编程2 天前
FastAPI性能优化技巧
后端·python·性能优化·fastapi·性能·codecapsule
力江3 天前
FastAPI 最佳架构实践,从混乱到优雅的进化之路
python·缓存·架构·单元测试·fastapi·分页·企业