跳到主要内容

第5节:用 SQLite 数据库替换写死的假数据

前面几天我们已经把电影推荐网站跑起来了,但所有电影数据都硬编码在 main.py 里,既不便于维护,也无法动态增删。今天这一步,我们要把假数据"搬家"到 SQLite 数据库中,并让接口从数据库读取数据。

整体链路:删除硬编码数据 → 编写初始化脚本建库建表 → 可视化验证数据 → 改造接口查询逻辑 → 启动测试 → 新增数据验证动态效果。


一、清理 main.py 中的硬编码数据​

打开项目中的 main.py,可以看到电影数据全部写死在文件里。我们把这部分整体删除,后续统一由数据库提供数据。

数据库选型上,关系型数据库(MySQL、PostgreSQL、SQLite 等)都可以胜任。MySQL/PostgreSQL 需要额外安装和配置,而 SQLite 轻量、免安装、就是一个文件,Python 内置 sqlite3 模块即可操作,非常适合本教程。因此本节课选用 SQLite。


二、编写初始化脚本:建库、建表、插入数据​

在项目目录下新建 init.py,用于一次性把电影数据写入数据库。

操作数据库的流程是统一的:连接数据库 → 创建游标对象 → 执行增删改查 → 提交并关闭。可以这样理解:连接是修好通往数据库的"高速公路",游标就是路上来回运送数据的"小货车"。

1. 连接数据库并创建游标​

import sqlite3

# 连接数据库(不存在则自动创建 movies.db 文件)
connection = sqlite3.connect('movies.db')
# 创建游标对象
cursor = connection.cursor()

2. 删除旧表并创建新表​

为保险起见,先删除可能存在的旧表,再创建新表:

# 删除数据表
cursor.execute('DROP TABLE IF EXISTS movies')

# 创建新的数据表
cursor.execute('''
CREATE TABLE movies (
id INTEGER PRIMARY KEY,
title TEXT,
year TEXT,
tags TEXT,
score REAL,
desc TEXT,
bg TEXT,
director TEXT,
actors TEXT,
video_url TEXT
)
''')

3. 循环插入数据(使用占位符防 SQL 注入)​

把原来的 movies_data 拷贝过来,用 for 循环逐条插入。字段值使用 ? 占位符,再传入真实值,可有效防止 SQL 注入:

# 插入数据
for movie in movies_data:
cursor.execute('''
INSERT INTO movies(id, title, year, tags, score, desc, bg, director, actors, video_url)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
movie['id'],
movie['title'],
movie['year'],
movie['tags'],
movie['score'],
movie['desc'],
movie['bg'],
movie['director'],
movie['actors'],
movie['video_url']
))

4. 提交、关闭并打印结果​

connection.commit()
connection.close()
print("数据库操作成功")

运行 init.py,终端输出"数据库操作成功",同时项目目录下新增了 movies.db 文件——这就是我们的数据库文件。

运行 init.py 后输出数据库操作成功并生成 movies.db 文件


三、用 Navicat 可视化验证数据​

打开 Navicat,新建 SQLite 连接,选择"现有数据库文件",指向项目目录下的 movies.db。连接成功后双击打开,可以看到新增的 movies 表,字段包括 id、title、year、tags、score、description、cover、director、actors、video_url。

以列表形式查看表数据,每一行就是一条电影记录,原来的假数据已全部入库。

在 Navicat 中查看 movies 表,确认电影数据已全部写入


四、改造 main.py:从数据库读取数据​

数据准备好后,回到 main.py,先写一个获取数据库连接的公共方法,再改造随机推荐和详情两个接口。

1. 封装数据库连接方法​

import sqlite3

def get_db_connection():
connection = sqlite3.connect('movies.db')
# 让查询结果可以像字典一样按字段名访问
connection.row_factory = sqlite3.Row
return connection

row_factory = sqlite3.Row 的作用是让查询结果支持 movie["id"]、movie["title"] 这样的字典式访问。

2. 随机推荐接口:SQL 随机排序取一条​

先在 Navicat 的查询窗口验证 SQL 是否正确:

SELECT * FROM movies ORDER BY RANDOM() LIMIT 1;

多次运行,每次返回的记录都不同,说明语句可用。建议先在可视化工具里验证 SQL,再写进 Python 代码,这样排查问题时能快速区分是 SQL 错误还是代码错误。

确认无误后写入接口:

@app.get('/api/movie/random')
async def get_random_movie():
# 从sqlite中随机筛选一条记录
connection = get_db_connection()
random_sql = "SELECT * FROM movies ORDER BY RANDOM() LIMIT 1"
movie = connection.execute(random_sql).fetchone()
connection.close()

if not movie:
raise HTTPException(status_code=404, detail='没有获取到电影')

return format_movie(movie)

这里 connection.execute() 会自动创建游标,因此省略了手动 cursor 的步骤。

3. 详情接口:按 ID 查询​

同样先在 Navicat 验证:

SELECT * FROM movies WHERE id = 4;

确认后写入代码,注意 ID 是动态的,必须用 ? 占位符并以元组传参(单元素元组也要带逗号):

@app.get('/api/movie/{movie_id}')
async def get_movie_by_id(movie_id: int):
connection = get_db_connection()
fetch_sql = "SELECT * FROM movies where id = ?"
movie = connection.execute(fetch_sql,(movie_id,)).fetchone()
connection.close()

if not movie:
raise HTTPException(status_code=404, detail='没有获取到电影')

return format_movie(movie)

五、启动测试与问题修复​

启动服务:

uvicorn main:app --reload

问题一:页面空白,SQL 变量引用顺序错误​

首次刷新页面没有任何输出。查看终端报错,提示 random_sql 在定义之前就被引用——把变量定义挪到使用之前即可,保存后服务自动重启。

问题二:演员列表显示异常​

修复后刷新,随机推荐正常,每次都是不同电影;点击"立即观看"进入详情页,能正确显示《沙丘》《星际穿越》《赛博朋克》等影片。

但详情页的演员列表显示成了整段字符串。原因是数据库里 actors 字段存的是逗号分隔的字符串,而前端需要列表。为此在连接方法下方新增一个统一的格式转换方法:

def format_movie(movie_row):
"""处理actors字段"""
movie_dict = dict(movie_row)
if movie_dict.get('actors'):
movie_dict['actors'] = movie_dict['actors'].split(',')
return movie_dict

在两个接口返回前分别调用 format_movie(movie)。刷新页面后,演员列表恢复正常显示。

改造后详情页正常显示演员列表


六、新增数据验证动态效果​

为了验证数据真正由数据库驱动,在 Navicat 中直接插入一条新记录:ID 为 5,片名"大熊课堂",年份 2025,标签科技/IT,评分 10 分,并补充封面、简介、导演、演员等信息。

回到网站刷新首页,随机推荐中出现了"大熊课堂",评分 10 分,点击进入详情页也能正常展示。这说明首页和详情页的数据完全来自数据库,新增记录会即时生效。

刷新首页后随机推荐到新插入的大熊课堂电影


小结​

本节完成了数据从代码到数据库的"搬家":

  1. 删除 main.py 中的硬编码电影数据;
  2. 编写 init.py,用 sqlite3 建库建表并批量插入数据,插入时使用 ? 占位符防止 SQL 注入;
  3. 用 Navicat 可视化确认数据入库,并养成"先验证 SQL、再写代码"的调试习惯;
  4. 在 main.py 中封装连接方法,用 ORDER BY RANDOM() LIMIT 1 实现随机推荐、用 WHERE id = ? 实现详情查询;
  5. 通过 format_movie 统一处理演员字段的字符串转列表;
  6. 在数据库中新增记录后刷新页面,验证了数据的动态生效。

至此,网站的数据层已切换为 SQLite,后续增删改查都只需操作数据库即可。

课程推荐

想系统学习这门课程?

你已阅读完本文。需要更完整的知识体系,可以继续了解「FastAPI 项目实战」。

查看课程详情