python对接mysql和模型类的故障

你疑惑的这两段代码(detail 接口的 mappings() 查询、Videos 模型类)本质上是「定义」和「查询实现」的关系,本身没有逻辑冲突,但存在「字段约束不匹配」和「查询方法兼容性」两个关键小坑 ,这也是为什么数据库有数据,查询后却取不到(显示 None)的核心原因。

我们先拆解两者的关联与差异,再给出针对性修正。

一、先明确:两段代码的核心关系

  1. class Videos(SQLModel, table=True):是数据库表的「抽象定义」,规定了表的字段名、字段类型、约束(必填/主键等),相当于给数据库表和 Python 代码之间搭了一座桥。
  2. session.execute(sql).mappings().first():是查询数据库的「实现方式」 ,目的是从数据库中取出数据,映射成 Python 可操作的对象,本应和 Videos 模型类匹配,但有两个坑导致映射失败。

二、关键差异/问题:导致数据查询后显示 None

问题1:Videos 模型类的字段约束过于严格,与 mappings() 兼容性差

你的 Videos 模型中,除了 videoidint|None(可选),其他字段(videotitlefilenamekeyword 等)都是必填类型(无 |None、无默认值) ,但 mappings() 返回的是「松散的 RowMapping 映射对象」,不遵守 Videos 模型的必填约束:

  • 若数据库中某个字段(比如 keywordreference)是 NULL(上传时未赋值),而模型类中定义为 str(必填),mappings() 映射时无法满足「必填 str」的约束,会直接将该字段置为 None,甚至连带影响其他非 NULL 字段的映射(比如 filenamesummary ,导致你打印时显示 None
  • scalars() 返回的是 Videos 模型实例,会严格遵守模型类的字段定义,自动处理「数据库 NULL 值」和「模型字段类型」的转换,兼容性更好。

问题2:Videos 模型缺少「自增属性」,与数据库自增字段不匹配

你的 videoid 定义:

python 复制代码
videoid:int|None=Field(default=None,primary_key=True)

虽然数据库中 videoid 大概率设置了「自增主键」,但模型类中缺少自增配置sa_column_kwargs={"autoincrement": True}),导致:

  • 模型类和数据库的「自增属性」不匹配,mappings() 映射时,无法正确识别 videoid 的取值,间接影响其他字段的查询结果映射,出现「数据库有值,查询后为 None」的现象。

问题3:mappings() vs scalars():查询结果的本质差异(核心)

这是最关键的一点,两者返回的结果完全不同,直接决定了能否取到数据:

查询方法 返回结果类型 Videos 模型的关联 取值稳定性
mappings().first() SQLAlchemy RowMapping(只读字典类似物) 无直接关联,仅做「列名-值」简单映射 差,容易丢失数据、出现 None
scalars().first() Videos 模型实例(严格遵守模型定义) 强关联,自动处理字段类型转换 高,100% 保留模型字段数据

简单说:mappings() 是「无差别映射」,不管你的 Videos 模型怎么定义,只按数据库返回的列名映射;scalars() 是「精准映射」,只返回符合 Videos 模型定义的实例,兼容性和稳定性远高于 mappings()

三、针对性修正(两步搞定,确保数据能正常取出)

步骤1:修正 Videos 模型类(匹配数据库,放宽合理约束)

python 复制代码
from sqlmodel import SQLModel, Field
from datetime import datetime

class Videos(SQLModel, table=True):
    # 修正1:补全自增属性,与数据库自增主键匹配
    videoid: int | None = Field(
        default=None, 
        primary_key=True, 
        sa_column_kwargs={"autoincrement": True}  # 新增:开启自增
    )
    # 修正2:核心字段(必须有值)保留必填,非核心字段加可选约束(|None),兼容数据库 NULL
    videotitle: str
    filename: str
    duration: int
    coursename: str
    content: str
    summary: str
    # 非核心字段:允许为 None(兼容数据库 NULL),避免映射失败
    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

步骤2:修正 detail 接口查询方法(改用 scalars(),转字典确保模板取值)

这是解决「None 问题」的核心,直接替换你现有 detail 接口:

python 复制代码
from fastapi import HTTPException  # 确保已导入

@app.get("/detail/{videoid}")
def detail(request: Request, videoid: int):
    with Session(engine) as session:
        sql = select(Videos).where(Videos.videoid == videoid)
        # 修正:改用 scalars() 获取 Videos 模型实例(而非 mappings())
        video_instance = session.execute(sql).scalars().first()

        if not video_instance:
            raise HTTPException(status_code=404, detail="该视频记录不存在")
        
        # 模型实例转普通字典,确保模板取值稳定
        video = video_instance.dict()

        # 调试打印:此时能看到真实数据,不会是 None
        print("===== 调试:查询到的视频数据 =====")
        print("文件名:", video.get("filename"))
        print("总结内容:", video.get("summary"))
        print("视频标题:", video.get("videotitle"))
        print("================================")

        return templates.TemplateResponse(
            request=request,
            name="detail.html",
            context={"video": video}
        )

四、验证效果

  1. 重启 FastAPI 服务(Ctrl+C 后重新运行代码);
  2. 访问 http://127.0.0.1:8000/detail/2
  3. 查看控制台打印:此时会显示数据库中的真实数据(比如 filename 是你的视频文件名,summary 是你的总结内容),不会再是 None
  4. 模板页面中,{``{ video['filename'] }}{``{ video['summary']|safe }} 会正常渲染出内容。

总结

  1. 两段代码无本质逻辑冲突,但存在「字段约束」和「查询方法兼容性」问题;
  2. 核心坑:mappings() 兼容性差,无法处理模型必填约束与数据库 NULL 值的矛盾,导致数据显示 None
  3. 关键解决:模型类补全自增+放宽非核心字段约束,查询改用 scalars() 获取模型实例并转字典。

按这个方法修正后,你的数据就能正常查询和显示了,不会再出现「数据库有值,查询后为 None」的现象。

相关推荐
weixin_433179332 小时前
Python -- 文件和异常
python
2301_822382762 小时前
开发一个简单的Python计算器
jvm·数据库·python
ValhallaCoder2 小时前
hot100-子串
数据结构·python·算法
lambert.wang2 小时前
当使用 uv 下载 Python 解释器时出现异常,通常是因为网络连接问题导致无法从 GitHub 下载安装包
python·github·uv
2501_920999272 小时前
Django全栈开发入门:构建一个博客系统
jvm·数据库·python
码农阿豪2 小时前
影刀RPA与Java融合实践:打造高效智能的高铁票务解决方案
java·python·rpa
_F_y2 小时前
MySQL用户管理
android·mysql·adb
喵手2 小时前
Python爬虫实战:采集行业协会、研究机构等平台的政策文件列表与PDF链接批量收集系统,支持自动下载、分类归档和数据库管理(SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·sqlite持久化存储·采集行业协会、研究机构政策文件·pdf链接采集
龚礼鹏2 小时前
图像显示框架十一——BufferQueue的工作流程(基于Android 15源码分析)
java·网络·数据库