你现在遇到的报错pymysql.err.OperationalError: (1364, "Field 'videoid' doesn't have a default value"),核心原因是——videos表的videoid字段是主键(非空),但既没有开启「自增」属性,也没有设置默认值,插入数据时你没有手动传入videoid的值,MySQL 无法生成主键值,因此抛出错误并回滚事务。
从日志能看到,SQL 插入语句已经正确生成(包含所有字段值),但最终执行了ROLLBACK(回滚),就是因为videoid这个主键字段的值缺失,这是 SQLModel 定义主键时新手最容易踩的坑(仅标记primary_key=True不足以让 MySQL 自动生成主键值,还需要显式开启自增)。
一、报错根源详解(新手易懂版)
- 你在
model.py中定义videoid时,只写了Field(default=None, primary_key=True),生成的 MySQL 数据表中,videoid字段属性是「主键、非空、无默认值、非自增」。 - 插入数据时,你没有手动传入
videoid(也不应该手动传入,主键应自动唯一生成),MySQL 找不到videoid的有效值,无法完成插入,只能抛出「没有默认值」的错误。 - SQLAlchemy 捕获到 MySQL 错误后,执行事务回滚(
ROLLBACK),数据无法写入数据库,最终返回 500 错误。
二、解决方案:给主键添加「自增」配置(核心修正)
步骤 1:修正model.py中所有表的主键字段,开启自增
SQLModel 中,要让 MySQL 主键实现自增,需要在Field中通过sa_column_kwargs参数指定autoincrement=True(这是适配 MySQL 自增的关键配置)。
修改后的model.py中,主键字段定义示例(以Videos为例,其他表的主键也一并修正,避免后续踩坑):
# 以 Videos 表的 videoid 为例(其他表的 userid、examid、scoreid 同理修改)classVideos(SQLModel,table=True):__tablename__="videos"# 核心修改:添加 sa_column_kwargs={"autoincrement": True} 开启自增videoid:int|None=Field(default=None,primary_key=True,sa_column_kwargs={"autoincrement":True}# 开启 MySQL 主键自增)videotitle:strfilename:strduration:int# 其他字段保持不变...完整的修正后model.py主键部分(所有表统一修正):
fromsqlmodelimportcreate_engine,Field,SQLModelfromdatetimeimportdatetime engine=create_engine('mysql+pymysql://root:123456@localhost/test',echo=True,pool_pre_ping=True)classUsers(SQLModel,table=True):__tablename__="users"# 修正:开启自增userid:int|None=Field(default=None,primary_key=True,sa_column_kwargs={"autoincrement":True})username:strpassword:strrealname:str|None=Field(default=None)role:str|None=Field(default="user")createtime:datetime|None=Field(default_factory=datetime.now)classVideos(SQLModel,table=True):__tablename__="videos"# 修正:开启自增(核心解决 videoid 报错)videoid:int|None=Field(default=None,primary_key=True,sa_column_kwargs={"autoincrement":True})videotitle:strfilename:strduration:intcoursename:str|None=Field(default=None)content:str|None=Field(default=None)summary:str|None=Field(default=None)keyword:str|None=Field(default=None)reference:str|None=Field(default=None)xmindjson:str|None=Field(default=None)examjson:str|None=Field(default=None)createtime:datetime|None=Field(default_factory=datetime.now)classExams(SQLModel,table=True):__tablename__="exams"# 修正:开启自增examid:int|None=Field(default=None,primary_key=True,sa_column_kwargs={"autoincrement":True})videoid:int|None=Field(default=None,foreign_key="videos.videoid")question:str|None=Field(default=None)type:str|None=Field(default=None)answer:str|None=Field(default=None)score:int|None=Field(default=0)options:str|None=Field(default=None)createtime:datetime|None=Field(default_factory=datetime.now)classScores(SQLModel,table=True):__tablename__="scores"# 修正:开启自增scoreid:int|None=Field(default=None,primary_key=True,sa_column_kwargs={"autoincrement":True})userid:int|None=Field(default=None,foreign_key="users.userid")videoid:int|None=Field(default=None,foreign_key="videos.videoid")examid:int|None=Field(default=None,foreign_key="exams.examid")answer:str|None=Field(default=None)score:int|None=Field(default=0)createtime:datetime|None=Field(default_factory=datetime.now)# 建表函数不变defcreate_tables():SQLModel.metadata.create_all(engine)if__name__=="__main__":create_tables()步骤 2:删除旧数据表,重建新表(关键!旧表结构无法自动更新)
因为之前已经创建过videos等表,旧表的videoid字段没有自增属性,修改模型后必须删除旧表,重新创建,否则旧表结构不变,还是会报错。
方式 1:可视化工具删除(新手友好)
- 打开 Navicat/MySQL Workbench,连接
test数据库。 - 找到
users、videos、exams、scores四张表,右键点击每张表,选择「删除表」(或「Drop Table」)。 - 确认删除(所有旧数据会丢失,新手测试阶段无影响)。
方式 2:MySQL 命令行删除
- 登录 MySQL 命令行,切换到
test数据库:USE test; - 执行以下 SQL 语句删除旧表(回车执行,分号不可省略):
DROPTABLEIFEXISTSscores;DROPTABLEIFEXISTSexams;DROPTABLEIFEXISTSvideos;DROPTABLEIFEXISTSusers; - 看到
Query OK, 0 rows affected说明删除成功。
步骤 3:重新运行model.py,创建带自增主键的新表
- 终端切换到项目目录
D:\PythonProject,执行:python model.py - 观察终端输出,无红色报错,会生成新的建表 SQL 语句,其中
videoid字段会包含AUTO_INCREMENT关键字(自增配置生效)。 - 验证:可视化工具中刷新
test数据库,查看videos表的videoid字段,属性会显示「主键、非空、自增」。
步骤 4:重新测试上传接口,验证数据插入成功
- 终止当前运行的 FastAPI 服务(
Ctrl+C)。 - 重新运行
python D:\PythonProject\python-7.2.1.py启动服务。 - 再次上传视频测试,此时插入数据时,MySQL 会自动为
videoid生成唯一自增值(从 1 开始,依次递增),无需手动传入。
成功标志:
- 控制台无红色报错,接口返回
200 OK。 - 日志中会显示
COMMIT(而非ROLLBACK),表示事务提交成功。 - 可视化工具中,
videos表会出现新记录,videoid字段会自动填充为1(后续插入为2、3等)。
三、额外避坑(新手必看)
- 主键自增的适配差异:SQLModel 中,
primary_key=True只是标记主键,不同数据库的自增配置不同,MySQL 必须用sa_column_kwargs={"autoincrement": True},SQLite 则无需额外配置(自动自增)。 - 修改表结构后必须重建表:SQLModel 的
SQLModel.metadata.create_all(engine)只会创建「不存在的表」,不会更新已存在表的结构,因此修改字段属性后,必须先删除旧表再重建。 - 避免手动传入主键值:自增主键的核心是自动生成唯一值,手动传入会破坏自增逻辑,甚至导致主键冲突(重复值)。
- 数据类型匹配:
videoid是int类型,自增字段只能是整数类型,不可改为str类型。
总结
- 核心报错原因:
videoid主键无自增、无默认值,插入数据时缺失值导致事务回滚。 - 解决关键:给主键添加
sa_column_kwargs={"autoincrement": True}开启 MySQL 自增,删除旧表重建新表。 - 避坑要点:修改表结构后需重建表,自增主键无需手动传入值,不同数据库自增配置有差异。
完成以上操作后,你的项目就能成功将视频数据写入 MySQL 数据库,全流程(上传→音频提取→语音识别→数据持久化)正常运行,后续扩展其他表时也不会再出现类似的主键默认值错误。