大家好,我是Kuls。
这是《小白学FastAPI》系列的第三篇文章。
今天我们主要讲的是FastAPI快速搭建一个博客系统。
这里可能有些小伙伴就懵了,我啥都不会的,怎么就让我来写个博客?
别慌,K哥这里是想通过搭建一个博客系统的api框架来给大家具体讲讲FastAPI里面的相关知识。
我们将会实现博客的几个功能:
•博客首页•单篇博客页面•某篇博客评论内容•获取未发布状态的博文•发布博客
这里大家需要注意,我们编写的只是博客的后端api的大致框架,如果有数据库等操作的内容,我们会放在后面说的。
一般我们写项目,首先可以先把简单的部分给写出来,这样我们整体项目的雏形也就可以慢慢形成。
在上述的几个功能里,博客首页其实是最简单的。
当然在我们编写代码之前,我们需要去创建虚拟环境、创建main.py、安装相关的依赖。
不管我们要写啥功能,导入fastapi,创建fastapi实例的操作是必备的:
from fastapi import FastAPI app = FastAPI()
博客首页
博客首页其实是最简单就可以实现的。
# 博客首页 @app.get('/blog') def index(): return {'data': '我是博客首页'}
直接一个get请求,路径我们设置为 /blog ,return 返回的内容我们先随便模拟一些数据,后续我们会继续完善。
实现的效果:
但是大家有没有发现一个问题。
因为我们有一个功能是获取未发布状态的博文
,这说明我们每一篇博文是有属于它自己的状态的,也就是 发布 和 未发布。
所以这里我们需要有一个参数来代表我们是想要获取发布的还是未发布的。
为了更加完善,我们也可以加入一些limit、sort等参数
http://127.0.0.1:8000/blog?published=true&&limit=10&&sort=pushlish_at
最终我们是想通过上述的访问得到相应的博文列表。
代码实现:
from fastapi import FastAPI from typing import Optional app = FastAPI() # 博客首页 @app.get('/blog') def index(limit: int = 10, published: bool = True, sort: Optional[str] = None): return {'data': f'我是博客首页,显示{limit}篇内容,并且发布状态为{published},排序顺序是根据{sort}字段'}
def index(limit: int = 10, published: bool = True, sort: Optional[str] = None):
这行代码中 limit: int = 10,其实就是将limit的默认值设为10,published同理。
sort: Optional[str] = None,其中的Optional是我们从typing第三方库中导入的,意思就是可选的,也就意味着sort这个参数我们也可以不设置。
http://127.0.0.1:8000/blog?published=true&&limit=10 这样访问也是正确的。
最后,实现的效果:
单篇博客页面
单篇博客页面这里就涉及到了fastapi中的路径参数。
当你去观察很多的博客时,你会发现大多数都是通过 /blog/数字
这种形式来定义的。
所以在这里我们也给每一篇博客一个id,然后直接通过 http://127.0.0.1:8000/blog/1 就能够访问到id为1的博客。
@app.get('/blog/{id}') def showblog(id: int): return {'data': f'这是id为 {id} 的博文'}
这里可以看到,我们设置了一个路径参数 {id},并且我们把它设置成了int类型。
实现的效果:
某篇博客评论内容
这个其实也很简单,跟我们单篇博客页面其实差不很多。
@app.get('/blog/{id}/comments') def comments(id: int): return {'data': f'这是id为{id}的博文评论内容'}
其中主要的区别就在于路径参数,我们后面加了一个comments来代表评论。
最后,访问的效果:
获取未发布状态的博文
想要拿到未发布状态的博文,其实逻辑很简单,我们在具体逻辑中判断一下就行了,这里会在后面文章中详细写。
具体函数:
@app.get('/blog/unpublished') def unpublished(): return {'data': '这里是没有发布的博文列表'}
当我们写完这个函数之后
去访问 http://127.0.0.1:8000/blog/unpublished
竟然报错了!?
为啥,我们具体看一下报错信息
是因为我们在上面写了一个访问单篇博文的函数
@app.get('/blog/{id}') def showblog(id: int): return {'data': f'这是id为 {id} 的博文'}
大家可以发现
@app.get('/blog/{id}')
@app.get('/blog/unpublished')
这两个路由非常的相似,只是后面一部分不同,可能有些读者就发现不对了,报错信息说我们传入的值不是一个合法的整型。
这说明fastapi它每次去查看路径时,是按照代码的从上到下的顺序来的。
所以它首先访问的是@app.get('/blog/{id}')的路由,而不是@app.get('/blog/unpublished')。
我们特别需要注意这一点!这在fastapi的编写当中非常重要!
那怎么解决这个问题?
我们直接将@app.get('/blog/unpublished')路径下的函数放在上面,这样fastapi首先就会访问到它,同时也不会影响@app.get('/blog/{id}')。
这个问题就完美的解决了!
发布博客
在之前的功能中,我们使用的都是fastapi中的get请求,在这个功能里,我们将会使用post来实现。
在实现发布博客前,我们得首先了解一下模型
这个概念。
学过flask或者Django的读者应该知道这个玩意,没学过也没关系,你可以理解为就是一个class类,继承了一个基类BaseModel。
其中的BaseModel,我们是从pydantic第三方库导入进来的。
下面就是我们实现的一个简单的Blog的基类
class Blog(BaseModel): title: str content: str published: Optional[bool]
title就是我们博文的标题,content就是内容,published表示的状态。
下面我们把基本的框架写好,看看能不能获取到post提交过来的值。
@app.post('/blog') def new_blog(blog: Blog): return {'data': f'博文标题:{blog.title},博文内容:{blog.content},博文发表状态:{blog.published}'}
大家可以看到@app.post('/blog'),此处是post方法了。并且在函数的参数中,我们使用的是上面建的class Blog
在编写的时候,fastapi的特性也体现出来了,IDE给了我们相应的提示,这也加快了我们的开发速度。
怎么去测试post呢?
你可能忘记了fastapi中的swagger!
我们下面用swagger来测试一下这个接口
大家可以看到成功的返回了!
总结
好了,前面两篇文章没有写过总结,今天还是给大家写一个总结吧。
这篇文章的目的其实就是教大家熟练掌握路径参数、查询参数、模型、请求方法这几个方面,整篇文章中也给大家讲述了一些细节问题。K哥还是希望大家能够认真阅读文章并且自己动手写一下,代码我也会放在文末。
本系列代码仓库:https://github.com/hellokuls/fastapi/tree/master
小白学FastAPI系列文章汇总: