从零开始写博客系统——新增查询修改
背景
前面我们搭建了博客系统,并且使用模拟数据写了一个查询博客列表的接口。
本文我们继续博客系统。
业务场景
进入一个博客系统,除了展示列表之外,还要能够查询博客正文的明细。
作为博客的博主,还需要能够新增文章和修改文章。
代码调整
由于没有使用数据库,我们的数据暂时会放在内存中。因此要对原来的代码结构做一下调整。
Articles
类在初始化的时候,就加载data.py
中的数据,而不是在查询列表的时候再加载数据。因此在__init__
中添加初始化代码。
article.py
class Articles(object):
def __init__(self):
self.articles = []
self.total = 0
for x in data.article_list:
at = Article(
x.get("id"),
x.get("title"),
x.get("content"),
x.get("author"),
x.get("created_time"),
x.get("modified_time"),
x.get("category"),
x.get("tag")
)
self.append(at)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
我们在app.py
中引入这个类进行初始化。
由于在Articles
的初始化代码中已经加载了数据,article_list
函数中就不需要加载模拟数据了,因此这里直接返回这个对象即可。
app.py
import time
from flask import Flask, jsonify, request
import article
app = Flask(__name__)
articles = article.Articles()
@app.route('/')
def hello():
return "Hello World!"
@app.route("/article_list")
def article_list():
return jsonify({"code": 0, "msg": "success", "data": articles.to_json()})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
查询文章详情页
查询文章,我们使用GET方法,在查询的时候,我们会带一个文章ID的参数。
url大概是这样:http://127.0.0.1:5000/get_article?id=1
我们的文章信息都在Articles这个类中管理,因此我们要在这里添加一个查询的方法。
article.py
class Articles(object):
......
def get_by_id(self, id: int):
for x in self.articles:
if x.id == id:
return x
return None
2
3
4
5
6
7
8
9
10
11
然后我们新增一个查询的接口即可。
app.py
@app.route("/get_article")
def get_article():
_id = request.args.get("id")
a = articles.get_by_id(int(_id))
if a:
return jsonify({"code": 0, "msg": "success", "data": a.to_dict()})
else:
return jsonify({"code": 1, "msg": "fail", "data": {}})
2
3
4
5
6
7
8
9
10
其中 request.args.get
方法就是获取url 后面的参数。
我们可以启动服务看看结果。
curl 'http://127.0.0.1:5000/get_article?id=1'
>>
{"code":0,"data":{"author":"\u70b9\u70b9\u5bd2\u5f6c","category":"\u4ece\u96f6\u5f00\u59cb\u5b66\u535a\u5ba2","content":"\u6211\u4ece2015\u5e74\u5e95\u5f00\u59cb\u6162\u6162\u7684\u5b66\u4e60\u7f16\u7801\u76f8\u5173\u7684\u77e5\u8bc6\u3002\u5728\u8fd9\u4e2a\u535a\u5ba2\u6211\u628a\u81ea\u5df1\u5b66\u4e60\u7684\u8bb0\u5f55\u5168\u90e8\u90fd\u8bb0\u4e86\u4e0b\u6765\uff0c\u8fd9\u4e48\u591a\u5e74\u8fc7\u53bb\u4e86\uff0c\u7248\u672c\u4e0d\u505c\u7684\u5728\u66f4\u66ff\uff0c\u5f53\u5e74\u7684\u90a3\u4e2a\u7cfb\u5217\u786e\u5b9e\u5df2\u7ecf\u6ca1\u5565\u53c2\u8003\u610f\u4e49\u4e86\uff0c\u5e76\u4e14\u53d7\u9650\u4e8e\u5f53\u65f6\u7684\u6c34\u5e73\uff0c\u5199\u51fa\u6765\u7684\u4e1c\u897f\u4e5f\u6ca1\u5565\u4ef7\u503c\uff0c\u751a\u81f3\u5728\u67d0\u4e9b\u65f6\u5019\u4f1a\u8bef\u5bfc\u521d\u5b66\u8005\uff0c\u56e0\u6b64\u51b3\u5b9a\u91cd\u65b0\u5199\u4e00\u4e0b\u8fd9\u4e2a\u7cfb\u5217\u7684\u5185\u5bb9\uff0c\u5982\u679c\u53ef\u4ee5\u7684\u8bdd\uff0c\u4e5f\u914d\u5957\u5f55\u5236\u4e00\u4e9b\u89c6\u9891\uff0c\u65b9\u4fbf\u540e\u6765\u4eba\u5b66\u4e60\u3002","created_time":"2022-04-01 11:12:21","id":1,"modified_time":"2022-04-23 11:12:21","tag":["Python","Flask","\u535a\u5ba2"],"title":"\u5f00\u7bc7"},"msg":"success"}
2
3
4
5
6
可以看到,我们模拟的id为1的数据就查询到了。
ps: 这里data
里面的数据打出来是unicode
编码的,这个没关系,只是一个编码的问题,前端在获取数据的时候,这个编码的字符会变成中文。
新增数据
新增数据我们使用POST
方法。在新增成功之后,接口一般会返回这个新增的ID
,方便前端跳转到这篇文章的详情页面。
新增数据必须要使用POST
方法,因此我们的接口需要对请求的方法做一下限定。同时也要从POST
过来的数据中获取文章的信息。然后添加到内存中(后续是数据库中)代码如下:
@app.route("/add_article", methods=["POST"])
def add_article():
title = request.get_json().get("title")
content = request.get_json().get("content")
author = request.get_json().get("author")
category = request.get_json().get("category")
tag = request.get_json().get("tag")
now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
idx = articles.total + 1
a = article.Article(
idx, title, content, author, now, now, category, tag)
articles.append(a)
return jsonify({"code": 0, "msg": "success", "data": {"insert_id": idx}})
2
3
4
5
6
7
8
9
10
11
12
13
这里的methods=[”POST”]
就限定了请求方法只能是POST
。
一般来说,新增数据的ID
在数据库中是一个自增的字段,用户是不需要感知这个ID
的,但是我们现在是模拟数据,因此这里这个自增的序号需要我们自己去计算。
写上代码之后我们可以验证一下。
curl -X POST -H "Content-Type: application/json" -d '{"title": "test_title", "content": "test_content", "author": "testuser", "category": "python", "tag": ["Python","test"]}' http://127.0.0.1:5000/add_article
>>
{"code":0,"data":{"insert_id":3},"msg":"success"}
--------------------------------------------------------------------
curl 'http://127.0.0.1:5000/get_article?id=3'
>>
{"code":0,"data":{"author":"testuser","category":"python","content":"test_content","created_time":"2022-04-24 20:58:28","id":3,"modified_time":"2022-04-24 20:58:28","tag":["Python","test"],"title":"test_title"},"msg":"success"}
2
3
4
5
6
7
8
9
10
11
12
13
修改数据
修改数据和新增数据一样,也要POST
的方法,与新增不同的是我们在修改的时候需要传一个ID
字段来标记我们修改的是哪个记录。
在Articles
类中增加修改的方法
article.py
class Articles(object):
......
def update_by_id(self, id: int, article: Article):
for i, x in enumerate(self.articles):
if x.id == id:
self.articles[i] = article
return True
return False
2
3
4
5
6
7
8
9
10
11
12
然后我们在接口中实现这个修改
@app.route("/update_article", methods=["POST"])
def update_article():
_id = request.get_json().get("id")
title = request.get_json().get("title")
content = request.get_json().get("content")
author = request.get_json().get("author")
category = request.get_json().get("category")
tag = request.get_json().get("tag")
now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
a = articles.get_by_id(int(_id))
if a:
a.title = title
a.content = content
a.author = author
a.category = category
a.tag = tag
a.modified_time = now
articles.update_by_id(int(_id), a)
return jsonify({"code": 0, "msg": "success", "data": {}})
else:
return jsonify({"code": 1, "msg": "fail", "data": {}})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
接下来是测试一下代码
curl -X POST -H "Content-Type: application/json" -d '{"id": 3, "title": "test_title_test", "content": "test_content", "author": "testuser", "category": "python", "tag": ["Python","test"]}' http://127.0.0.1:5000/update_article
{"code":0,"data":{},"msg":"success"}
--------------------------------------------------------------------
curl 'http://127.0.0.1:5000/get_article?id=3'
{"code":0,"data":{"author":"testuser","category":"python","content":"test_content","created_time":"2022-04-24 20:58:28","id":3,"modified_time":"2022-04-24 21:01:55","tag":["Python","test"],"title":"test_title_test"},"msg":"success"}
2
3
4
5
可以看到,title
字段已经被修改了。
总结
回顾一下,本文我们学习了如何新增文章,修改文章,查询文章的详情。同样的,我们会放到代码仓库中管理起来。
git add article.py
git add app.py
git commit -m'add insert qry update api'
git push origin master
2
3
4
同样的,如果尝试了很久依然无法运行服务的同学,可以参考:代码浏览 - blog - 从零开始写一个博客系统 - svenweng (coding.net) 的代码。
思考
如果读者足够细心可以发现,这个修改接口其实是有问题的,按照实际的场景来看,我如果只修改title
,那么只要传title
就可以了,其他字段不需要传。如果你尝试了这么请求,你就会发现原来有的数据变成null
了。
怎么修改才能实现传哪个字段,就修改哪个字段,其他的值保持不变?