新闻详情
获取新闻详情
I.请求与响应过程
当用户访点击首页的某个新闻信息时,页面回跳转到新闻详情页,此时前端回向后端发送详情信息请求
flowchart LR
subgraph B [后端]
U[FastAPI服务]
end
subgraph A [详情页界面]
direction LR
F1[新闻详情]
end
A -- ① 请求分类<br> /api/news/detail --> B
B -- ② 返回响应 <br> {code: 200,message: success,data: [{id: 1,title: 新闻标题,image: 图片URL,author: 作者,publishTime: 发布时间,categoryId: 1,views: 1000}]} --> A
II. 路由定义
在news.py文件,编写路由解析代码
| ## ...............
## 其他代码
## ...............
@router.get("/detail")
async def read_news_detail(news_id: int=Query(..., alias="id"), db: AsyncSession = Depends(get_db)):
"""
获取新闻详情接口
Args:
news_id (int): 新闻ID,必填参数,通过查询参数id传入
db (AsyncSession): 通过依赖注入获取的数据库会话对象
Example:
GET /api/news/detail?id=1
"""
return {
"code": 200,
"message": "success",
"data": "新闻详情"
}
|

在main.py文件中已经对路由文件进行过注册,无需再操作
重启FastAPI服务,运行测试,检查定义的路由接口是否能够处理前端发送的请求

III. 定义模型类
新闻数据表的模型已经定义,无需再进行定义
IV. 编写ORM数据操作
在news.py文件,将新闻模块的数据操作按照对应的逻辑编写代码
实现功能如下:
- 根据id获取新闻信息
- 增加新闻访问量,通过update将新闻表中的views字段进行更新
- 获取关联新闻,通过分类id将当前分类下的新闻返回
| from sqlalchemy import select,func,update
from sqlalchemy.exc import NoResultFound
## ...............
## 其他代码
## ...............
async def get_news(db: AsyncSession, news_id: int):
"""
根据新闻ID获取单条新闻详情
Args:
db (AsyncSession): SQLAlchemy异步数据库会话对象
news_id (int): 新闻的唯一标识ID
Returns:
Optional[News]: 返回对应的新闻对象,如果新闻不存在则返回None
Example:
# 获取ID为1的新闻
news = await get_news(db, news_id=1)
if news:
print(f"新闻标题: {news.title}")
else:
print("新闻不存在")
"""
try:
stmt = select(News).where(News.id == news_id)
result = await db.execute(stmt)
return result.scalar_one_or_none()
except NoResultFound:
return None
async def increment_views(db: AsyncSession, news_id: int):
"""
增加新闻浏览量
Args:
db: 数据库会话
news_id: 新闻ID
Returns:
bool: 更新成功返回True,新闻不存在返回False
"""
# 使用UPDATE语句直接更新
result = await db.execute(
update(News)
.where(News.id == news_id)
.values(views=News.views + 1)
)
# 提交更改
await db.commit()
# 检查是否有行被更新
if result.rowcount > 0:
return True
else:
return False
async def get_related_news(db: AsyncSession, news_id: int, category_id: int, limit: int = 5):
"""
获取相关新闻
Args:
db: 数据库会话
news_id: 当前新闻ID
category_id: 当前新闻分类ID
limit: 返回相关新闻数量限制
Returns:
相关新闻列表
"""
# 查询同分类下的其他新闻,排除当前新闻
query = select(News).where(
News.id != news_id,
News.category_id == category_id
).order_by(
News.views.desc(),
News.publish_time.desc()
).limit(limit)
result = await db.execute(query)
related_news = result.scalars().all()
# 转换为字典格式返回
return [
{
"id": news.id,
"title": news.title,
"content": news.content,
"image": news.image,
"author": news.author,
"publishTime": news.publish_time,
"categoryId": news.category_id,
"views": news.views
}
for news in related_news
]
|

V. 路由中实现数据操作
回到对应的路由中,调用刚才编写好的数据处理函数。
| from fastapi import APIRouter, Depends, Query, HTTPException
## ...............
## 其他代码
## ...............
@router.get("/detail")
async def read_news_detail(news_id: int=Query(..., alias="id"), db: AsyncSession = Depends(get_db)):
"""
获取新闻详情接口
Args:
news_id (int): 新闻ID,必填参数,通过查询参数id传入
db (AsyncSession): 通过依赖注入获取的数据库会话对象
Example:
GET /api/news/detail?id=1
"""
new = await news.get_news(db, news_id)
if not news:
raise HTTPException(status_code=404, detail="新闻不存在")
# 增加浏览量
await news.increment_views(db, news_id)
# 获取相关新闻
related_news = await news.get_related_news(db, news_id, new.category_id)
return {
"code": 200,
"message": "success",
"data": {
"id": new.id,
"title": new.title,
"content": new.content,
"image": new.image,
"author": new.author,
"publishTime": new.publish_time, # 注意字段名映射
"categoryId": new.category_id, # 注意字段名映射
"views": new.views,
"relatedNews": related_news
}
}
|

重启FastAPI服务,测试数据是否正常返回

启动前端服务检查数据是否正常加载
