我复现一下上面的操作说 zq-platform初始数据写不到数据库 第一次执行-
alembic revision --autogenerate -m "init tables"
报错
INFO [[ alembic.runtime.migration]
](http://alembic.runtime.migration]) Context impl PostgresqlImpl.INFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Will assume transactional DDL.ERROR [[
alembic.util.messaging]
](http://alembic.util.messaging]) Target database is not up to date.FAILED: Target database is not up to date.
意思是:你的数据库当前版本 (current) 落后于 Alembic 迁移脚本所定义的最新版本 (head) cnblogs.com+1。这就好比你手里拿着的是第3版的说明书,但产品已经更新到第5版了
要解决这个问题,核心思路就是将数据库的当前版本 (current) 更新到与最新的迁移脚本版本 (head) 一致。
1.查看当前数据库状态:首先,确认一下版本差异。在项目根目录下打开终端,依次运行:
# 查看数据库当前记录的版本 alembic current # 查看所有可用的迁移脚本版本(head) alembic heads
你通常会看到 current 的版本号比 heads 的版本号要旧,或者 heads 显示了多个分支(这通常意味着存在多个分支迁移需要合并)。 分别显示
INFO [[ alembic.runtime.migration]
](http://alembic.runtime.migration]) Context impl PostgresqlImpl.INFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Will assume transactional DDL.
这证实了问题所在:数据库当前停留在一个空版本,并没有处于最新状态,所以 Alembic 拒绝你生成新的迁移脚本。
请直接运行下面这条命令来解决这个问题:
alembic upgrade head
这个命令会扫描 alembic/versions 文件夹,找到所有脚本,并依次在数据库中执行它们。
执行结果:
INFO [[ alembic.runtime.migration]
](http://alembic.runtime.migration]) Context impl PostgresqlImpl.INFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Will assume transactional DDL.INFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Running upgrade -> b6a31168d666, init tablesINFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Running upgrade b6a31168d666 -> a79453452d83, add page design
数据库已经成功升级到最新版本了。从输出 Running upgrade b6a31168d666 -> a79453452d83 可以看到:数据库已经更新到了 a79453452d83,
打开数据库可以看到当前版本号:
重新生成迁移:现在可以再次尝试运行 alembic revision --autogenerate -m “init tables”。
alembic revision --autogenerate -m "init tables"
显示结果:
INFO [[ alembic.runtime.migration]
](http://alembic.runtime.migration]) Context impl PostgresqlImpl.INFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Will assume transactional DDL.Generating F:\下载程序与源码\★★★可执行项目收集★★★\zq-platform\backend-fastapi\alembic\versions\588[
bd64ec92e_init_tables.py
](http://bd64ec92e_init_tables.py) ... done
输出显示:Generating ... 588bd64ec92e_init_tables.py ... done
这表示 Alembic 成功扫描了你的代码和数据库,并发现它们之间的差异,自动生成了一个新的迁移脚本文件: 588bd64ec92e_init_tables.py。 接下来的步骤:让修改生效 现在脚本文件只是生成了,但数据库里的表结构还没变。你需要执行最后一步:
- 查看生成的脚本(可选,但推荐) 你可以打开 alembic\versions[ 9abfcdbaff03_init_tables.py ](http://9abfcdbaff03_init_tables.py) 看一眼。检查 upgrade() 函数里是否包含了 op.create_table(…) 等语句。如果那里是空的,说明 Alembic 没检测到你的模型变化,或者模型没有被正确导入。
- 更新数据库(必须执行) 在终端运行:
alembic upgrade head
这将会把刚才生成的脚本应用到你的 fastapi_db 数据库中,创建对应的表结构。
显示
INFO [[ alembic.runtime.migration]
](http://alembic.runtime.migration]) Context impl PostgresqlImpl.INFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Will assume transactional DDL.INFO [[
alembic.runtime.migration]
](http://alembic.runtime.migration]) Running upgrade a79453452d83 -> 588bd64ec92e, init tables
数据库迁移已经完全成功了!🎉
从输出 Running upgrade a79453452d83 -> 588bd64ec92e 可以确认:
你的 fastapi_db 数据库已经成功应用了 init tables 脚本,所有定义的表结构现在都已经真实存在于数据库中了。 验证成果 如果你想确认表真的创建好了,可以:
1.打开 pgAdmin(如果你安装了的话)。
2.连接到 fastapi_db。
3.展开 Schemas -> public -> Tables。
4.你应该能看到刚才定义的所有数据表(比如 users 等)。
或者,你可以直接在 Python 代码中试着向数据库写入一条数据,看是否报错。
再执行python scripts/ loaddata.py db_init.json,导入数据,看到
导入完成: 成功: 38 条 失败: 0 条
先不要激动!!!日志最后一句“导入完成: 成功 38 条 / 失败 0 条”是脚本自己打印的统计,并不真实——
只要发生 ROLLBACK,整个事务就被回滚,数据库里一条新数据也没有写进去。
真正的失败原因就是这一条:
[
asyncpg.exceptions.DataError:
](http://asyncpg.exceptions.DataError:) invalid input for query argument $4: '2026-01-11T19:44:39.752685' (expected a [
datetime.date
](http://datetime.date) or [
datetime.datetime
](http://datetime.datetime) instance, got 'str')
也就是 core_user.last_login 字段传的是 字符串,而数据库列类型是 timestamp without time zone,异步驱动 asyncpg 不接受字符串隐式转换。
如何修复-
def parse_datetime(value): """解析日期时间字符串""" if isinstance(value, str): # 尝试多种日期时间格式 formats = [ "%Y-%m-%dT%H:%M:%S.%f", # ISO 格式带微秒 "%Y-%m-%dT%H:%M:%S", # ISO 格式不带微秒 "%Y-%m-%d %H:%M:%S.%f", # 带微秒的空格分隔格式 "%Y-%m-%d %H:%M:%S", # 不带微秒的空格分隔格式 "%Y-%m-%d", # 仅日期格式 ] for fmt in formats: try: return [
datetime.strptime(value,
](http://datetime.strptime(value,) fmt) except ValueError: continue # 如果以上格式都不匹配,尝试 fromisoformat try: return [
datetime.fromisoformat(value.replace(
](http://datetime.fromisoformat(value.replace()"Z", "+00:00")) except ValueError: pass # 如果所有尝试都失败,返回原始值 return value return value ...... # 转换日期时间字段 for key, value in [
fields.items():
](http://fields.items():) if isinstance(value, str): # 检查是否为日期时间格式的字符串 parsed_value = parse_datetime(value) # 如果成功解析且返回的是 datetime 对象,则替换原值 if isinstance(parsed_value, datetime): fields[key] = parsed_value
再执行python scripts/ loaddata.py db_init.json,直至这些数据都导入完成。
当看到-
从文件导入数据: [
db_init.json
](http://db_init.json)读取到 38 条记录2026-01-20 17:07:52,224 INFO [
sqlalchemy.engine.Engine
](http://sqlalchemy.engine.Engine) select [
pg_catalog.version()
](http://pg_catalog.version())2026-01-20 17:07:52,225 INFO [
sqlalchemy.engine.Engine
](http://sqlalchemy.engine.Engine) [raw sql] ()......2026-01-20 17:07:52,276 INFO [
sqlalchemy.engine.Engine
](http://sqlalchemy.engine.Engine) COMMIT导入完成: 成功: 38 条 失败: 0 条
·脚本成功读取了
db_init.json
文件,识别出包含 38 条待导入的记录·SQLAlchemy 引擎成功连接到 PostgreSQL 数据库(日志中出现
pg_catalog.version()
是 PostgreSQL 特有的查询)数据库验证
出现账号数据即为数据导入成功。
启动服务-
python main.py或使用 uvicornuvicorn main:app --reload --host 0.0.0.0 --port 8000
这样初始数据写不到数据库问题就可以得到根本解决。