title: 使用Tortoise-ORM和FastAPI构建评论系统

date: 2025/04/25 21:37:36

updated: 2025/04/25 21:37:36

author: cmdragon

excerpt:

在models.py中定义了Comment模型,包含id、content、created_at、updated_at字段,并与User和Article模型建立外键关系。schemas.py中定义了CommentBase、CommentCreate、CommentUpdate和CommentResponse等Pydantic模型,用于数据验证和响应。路由层实现了创建、获取和删除评论的API,使用get_or_none处理不存在的评论,并捕获异常。测试接口通过requests进行创建和异常测试。常见报错包括外键约束失败、验证错误和事件循环未关闭,需检查外键值、请求体匹配和正确关闭事件循环。

categories:

  • 后端开发
  • FastAPI

tags:

  • Tortoise-ORM
  • Pydantic
  • FastAPI
  • 评论系统
  • 数据库模型
  • 数据验证
  • 接口测试


扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意https://tools.cmdragon.cn/

一、Tortoise-ORM模型定义

我们首先在models.py中定义评论模型:

from tortoise.models import Model
from tortoise import fields class Comment(Model):
id = fields.IntField(pk=True)
content = fields.TextField()
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True) # 外键关系
user = fields.ForeignKeyField('models.User', related_name='comments')
article = fields.ForeignKeyField('models.Article', related_name='comments') class Meta:
table = "comments"
indexes = ("created_at", "user_id", "article_id") def __str__(self):
return f"Comment {self.id} by {self.user.username}"

代码解析:

  1. auto_now_add会在创建时自动记录时间
  2. 通过related_name建立双向关联查询路径
  3. 复合索引提升常用查询条件的效率
  4. 继承Model基类获得ORM能力

二、Pydantic模型定义

在schemas.py中定义数据验证模型:

from pydantic import BaseModel
from datetime import datetime class CommentBase(BaseModel):
content: str
user_id: int
article_id: int class CommentCreate(CommentBase):
pass class CommentUpdate(BaseModel):
content: str class CommentResponse(CommentBase):
id: int
created_at: datetime
updated_at: datetime class Config:
orm_mode = True

验证要点:

  1. 创建模型继承自基础模型
  2. 更新模型仅允许修改内容字段
  3. 响应模型启用orm_mode以兼容ORM对象
  4. 时间字段自动转换时间格式

三、路由层实现

核心路由实现在comments.py中:

from fastapi import APIRouter, Depends, HTTPException
from .models import Comment
from .schemas import CommentCreate, CommentResponse router = APIRouter(prefix="/comments", tags=["comments"]) @router.post("/", response_model=CommentResponse)
async def create_comment(comment: CommentCreate):
try:
comment_obj = await Comment.create(**comment.dict())
return await CommentResponse.from_tortoise_orm(comment_obj)
except Exception as e:
raise HTTPException(
status_code=400,
detail=f"创建评论失败: {str(e)}"
) @router.get("/{comment_id}", response_model=CommentResponse)
async def get_comment(comment_id: int):
comment = await Comment.get_or_none(id=comment_id)
if not comment:
raise HTTPException(status_code=404, detail="评论不存在")
return comment @router.delete("/{comment_id}")
async def delete_comment(comment_id: int):
deleted_count = await Comment.filter(id=comment_id).delete()
if not deleted_count:
raise HTTPException(status_code=404, detail="评论不存在")
return {"message": "评论删除成功"}

技术要点:

  1. 使用get_or_none替代get避免直接抛出异常
  2. 批量删除返回影响行数作为判断依据
  3. 异常处理覆盖数据库操作的各种失败场景

四、测试接口

使用requests测试接口:

import requests

BASE_URL = "http://localhost:8000/comments"

# 创建测试
def test_create_comment():
data = {
"content": "优质技术文章!",
"user_id": 1,
"article_id": 1
}
response = requests.post(BASE_URL, json=data)
assert response.status_code == 200
print(response.json()) # 异常测试
def test_invalid_user():
data = {
"content": "错误测试",
"user_id": 999,
"article_id": 1
}
response = requests.post(BASE_URL, json=data)
assert response.status_code == 400
print(response.json())

五、课后Quiz

  1. 当查询不存在的评论ID时,应该返回什么HTTP状态码?

    A) 200

    B) 404

    C) 500

    D) 400

答案:B) 404。get_or_none方法会返回None,触发自定义的404异常

  1. 如何实现评论的软删除功能?

    A) 直接删除数据库记录

    B) 添加is_deleted字段

    C) 使用数据库回收站功能

    D) 修改内容为"已删除"

答案:B) 添加布尔型is_deleted字段,查询时过滤已删除的记录

六、常见报错处理

  1. 报错:tortoise.exceptions.IntegrityError: FOREIGN KEY constraint failed

    原因:尝试关联不存在的用户或文章ID

    解决:检查外键值是否存在,添加数据库约束

  2. 报错:pydantic.error_wrappers.ValidationError

    原因:请求体缺少必填字段或字段类型错误

    解决:检查请求体是否匹配schema定义,使用try-except捕获验证错误

  3. 报错:RuntimeError: Event loop is closed

    原因:异步操作未正确关闭

    解决:在main.py中添加关闭事件循环的hook:

from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise app = FastAPI() register_tortoise(
app,
db_url="sqlite://db.sqlite3",
modules={"models": ["app.models"]},
generate_schemas=True,
add_exception_handlers=True,
)

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:使用Tortoise-ORM和FastAPI构建评论系统 | cmdragon's Blog

往期文章归档:

使用Tortoise-ORM和FastAPI构建评论系统的更多相关文章

  1. Hexo快速构建个人小站-Fulid主题下添加Valine评论系统(三)

    Hexo目录: Hexo快速构建个人小站-Hexo初始化和将项目托管在Github(一) Hexo快速构建个人小站-自定义域名和自定义主题(二) 背景交代: 前面两章完成了Hexo的初始化和部分自定义 ...

  2. 能动手绝不多说:开源评论系统remark42上手指南

    能动手绝不多说:开源评论系统 remark42 上手指南 前言 写博客嘛, 谁不喜欢自己倒腾一下呢. 从自建系统到 Github Page, 从 Jekyll 到 Hexo, 年轻的时候谁不喜欢多折腾 ...

  3. 在TensorFlow中基于lstm构建分词系统笔记

    在TensorFlow中基于lstm构建分词系统笔记(一) https://www.jianshu.com/p/ccb805b9f014 前言 我打算基于lstm构建一个分词系统,通过这个例子来学习下 ...

  4. 应用集成-在Hexo、Hugo博客框架中使用Gitalk基于Github上仓库项目的issue无后端服务评论系统实践

    关注「WeiyiGeek」公众号 设为「特别关注」每天带你玩转网络安全运维.应用开发.物联网IOT学习! 希望各位看友[关注.点赞.评论.收藏.投币],助力每一个梦想. 本章目录 目录 0x00 Gi ...

  5. jQuery Mobile案例,最近用Moon.Web和Moon.Orm做了一套系统

      一.简介 先说说,我们的主题.jQuery Mobile,最近用Moon.Web和Moon.Orm做了一套系统 jQuery Mobile是jQuery 在手机上和平板设备上的版本.jQuery ...

  6. Linux From Scratch(从零开始构建Linux系统,简称LFS)- Version 7.7(二)

    七. 构建临时系统 1. 通用编译指南 a. 确认是否正确设置了 LFS 环境变量 echo $LFS b. 假定你已经正确地设置了宿主系统的符号链接: 1)shell 使用的是 bash. 2)sh ...

  7. 多说评论系统API调用和本地身份说明(JWT)

    多说评论系统是一个非常好用的第三方评论插件,聚合了大多数的SNS平台账号登录和分享功能,UI也很不错. 作为网站快速接入评论系统,多说是一个比较好的选择,其也提供了一些实用的API去满足定制化需求. ...

  8. 门户级UGC系统的技术进化路线——新浪新闻评论系统的架构演进和经验总结(转)

    add by zhj:先收藏了 摘要:评论系统是所有门户网站的核心标准服务组件之一.本文作者曾负责新浪网评论系统多年,这套系统不仅服务于门户新闻业务,还包括调查.投票等产品,经历了从单机到多机再到集群 ...

  9. Ajax制作无刷新评论系统

    index.html <script src="jquery.min.js"></script> <script> $(function(){ ...

  10. 给hexo添加评论系统

    默认主题 landscape 文件目录,comments为新建的 _config.yml layout -- _partial -- article.ejs |- comments -- disqus ...

随机推荐

  1. 从存钱罐到子数组:一个关于累加和的精妙问题|LeetCode 560 和为K的子数组

    LeetCode 560 和为K的子数组 点此看全部题解 LeetCode必刷100题:一份来自面试官的算法地图(题解持续更新中) 生活中的算法 你有没有这样的经历:每天往存钱罐里存一些零钱,某一天突 ...

  2. Linux 之 vi / vim

    vi / vim ​ Vim 是从 vi 发展出来的一个文本编辑器.代码补全.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用. 简单的来说, vi 是老式的字处理器,不过功能已经很齐全了 ...

  3. xcode 12.3 mac m1

  4. 在GitHub上部署个人静态网站

    在GitHub上部署个人静态网站 首先将网站设置文件上传到github的一个新建仓库,并公开仓库(会员可不用公开) 找到settings(设置)-page(页面)选项并进入 选择分支(root)并sa ...

  5. Hi3516EV200 编译环境配置及交叉编译软件包

    基础信息 OS: Ubuntu 16.04 xenial SDK 版本: Hi3516EV200R001C01SPC012 - Hi3516EV200_SDK_V1.0.1.1 SDK 包路径:Hi3 ...

  6. ABC392E翻译

    AT_abc392_e [ABC392E] Cables and Servers 题目描述 有编号从 \(1\) 到 \(N\) 的 \(N\) 台服务器和编号从 \(1\) 到 \(M\) 的 \( ...

  7. STM32实战——DHT11温湿度获取并展示

    介绍 DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,包括一个电阻式感湿元件和一个NTC测温元件,可以用来测量温度和湿度. 硬件连线 注意 本实验使用STM32F103C8T ...

  8. 来自deepseek:php禁止跨域请求

    在PHP中,禁止API被跨域调用可以通过设置HTTP响应头来实现.跨域资源共享(CORS,Cross-Origin Resource Sharing)是一种机制,允许浏览器从不同域名的服务器请求资源. ...

  9. postman 提示Http Status 400 -Bad Request

    Http Status 400 -Bad Request 将headers下面的选项全部勾选 新版postman自带的内容

  10. vim中文乱码 vim字符集设置

    vim中文乱码 vim字符集设置 vim的设置一般放在/etc/vimrc文件中,不过,建议不要修改它.可以修改~/.vimrc文件(默认不存在,可以自己新建一个),写入所希望的设置. set fil ...