代码改变世界

用 Flask 来写个轻博客 (36) — 使用 Flask-RESTful 来构建 RESTful API 之五

2017-01-02 21:07  云物互联  阅读(196)  评论(0编辑  收藏  举报

目录

前文列表

用 Flask 来写个轻博客 (1) — 创建项目
用 Flask 来写个轻博客 (2) — Hello World!
用 Flask 来写个轻博客 (3) — (M)VC_连接 MySQL 和 SQLAlchemy
用 Flask 来写个轻博客 (4) — (M)VC_创建数据模型和表
用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解
用 Flask 来写个轻博客 (6) — (M)VC_models 的关系(one to many)
用 Flask 来写个轻博客 (7) — (M)VC_models 的关系(many to many)
用 Flask 来写个轻博客 (8) — (M)VC_Alembic 管理数据库结构的升级和降级
用 Flask 来写个轻博客 (9) — M(V)C_Jinja 语法基础快速概览
用 Flask 来写个轻博客 (10) — M(V)C_Jinja 常用过滤器与 Flask 特殊变量及方法
用 Flask 来写个轻博客 (11) — M(V)C_创建视图函数
用 Flask 来写个轻博客 (12) — M(V)C_编写和继承 Jinja 模板
用 Flask 来写个轻博客 (13) — M(V)C_WTForms 服务端表单检验
用 Flask 来写个轻博客 (14) — M(V)C_实现项目首页的模板
用 Flask 来写个轻博客 (15) — M(V)C_实现博文页面评论表单
用 Flask 来写个轻博客 (16) — MV(C)_Flask Blueprint 蓝图
用 Flask 来写个轻博客 (17) — MV(C)_应用蓝图来重构项目
用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象
用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
用 Flask 来写个轻博客 (20) — 实现注册表单与应用 reCAPTCHA 来实现验证码
用 Flask 来写个轻博客 (21) — 结合 reCAPTCHA 验证码实现用户注册与登录
用 Flask 来写个轻博客 (22) — 实现博客文章的添加和编辑页面
用 Flask 来写个轻博客 (23) — 应用 OAuth 来实现 Facebook 第三方登录
用 Flask 来写个轻博客 (24) — 使用 Flask-Login 来保护应用安全
用 Flask 来写个轻博客 (25) — 使用 Flask-Principal 实现角色权限功能
用 Flask 来写个轻博客 (26) — 使用 Flask-Celery-Helper 实现异步任务
用 Flask 来写个轻博客 (27) — 使用 Flask-Cache 实现网页缓存加速
用 Flask 来写个轻博客 (29) — 使用 Flask-Admin 实现后台管理 SQLAlchemy
用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能
用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理
用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一
用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二
用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三
用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四

PUT 请求

紧接前 4 篇, 继续完成 PUT 和 DELETE 请求的实现.

  • PUT 请求对应的是资源类的 put() 方法, 表示更新操作. 所以仍然需要先定义 post_put 解析器
    vim jmilkfansblog/controllers/flask_restful/parsers.py
post_put_parser = reqparse.RequestParser()

post_put_parser.add_argument(
    'title',
    type=str)

post_put_parser.add_argument(
    'text',
    type=str)

post_put_parser.add_argument(
    'tags',
    type=str,
    action='append')

post_put_parser.add_argument(
    'token',
    type=str,
    required=True,
    help='Auth Token is required to update the posts.')

NOTE: 从 post_put_parser 解析器可以看见, 我们仅允许传入最多 4 个参数, 其中也一定不能缺少 token 以保证数据的安全性.

  • 定义资源类 PostApi 的 put() 更新方法
    vim jmilkfansblog/controllers/flask_restful/posts.py
...

    def put(self, post_id=None):
        """Will be execute when receive the HTTP Request Methos `PUT`."""

        if not post_id:
            abort(400)

        post = Post.query.filter_by(id=post_id).first()
        if not post:
            abort(404)

        args = parsers.post_put_parser.parse_args()
        user = User.verify_auth_token(args['token'])

        if not user:
            abort(401)
        if user != post.user:
            abort(403)

        if args['title']:
            post.title = args['title']
        if args['text']:
            post.text = args['text']
        if args['tags']:
            for item in args['tags']:
                tag = Tag.query.filter_by(name=item).first()
                if tag:
                    post.tags.append(tag)
                else:
                   new_tag = Tag()
                   new_tag.name = item
                   post.tags.append(new_tag)

        db.session.add(post)
        db.session.commit()

        return (post.id, 201)
...

NOTE: put() 方法和 post() 方法很相似, 所以这里不在赘叙.

DELETE 请求

DELETE 请求的实现是最简单的, 一般而言, 不需要返回任何的数据, 只需要返回正确的 HTTP status_int 就可以了.
vim jmilkfansblog/controllers/flask_restful/posts.py

    def delete(self, post_id=None):
        """Will be execute when receive the HTTP Request Method `DELETE`."""

        if not post_id:
            abort(400)

        post = Post.query.filter_by(id=post_id).first()
        if not post:
            abort(404)

        args = parsers.post_delete_parser.parse_args(strict=True)
        user = User.verify_auth_token(args['token'])
        if user != post.user:
            abort(403)

        # Will be delete relationship record with posts_tags too.
        # But you have to ensure the number of record equal with len(post.tags)
        db.session.delete(post)
        db.session.commit()

        return "", 204

测试

对一条已经存在的 posts 记录进行 update 操作

mysql> select * from posts where id='1746b650-bcab-436b-82ab-7411e252b576';
+--------------------------------------+-----------+-------+--------------+--------------------------------------+
| id                                   | title     | text  | publish_date | user_id                              |
+--------------------------------------+-----------+-------+--------------+--------------------------------------+
| 1746b650-bcab-436b-82ab-7411e252b576 | Just Test | Hello | NULL         | 65cb9792-b876-49e7-b2c5-46468624199e |
+--------------------------------------+-----------+-------+--------------+--------------------------------------+
1 row in set (0.00 sec)
  • 获取 Token
jmilkfan@JmilkFan-Devstack:/opt/JmilkFan-s-Blog$ curl -d "username=<username>" -d "password=<password>" http://localhost:8089/api/auth
{
    "token": "eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ4MzM2MjExNywiaWF0IjoxNDgzMzYxNTE3fQ.eyJpZCI6IjY1Y2I5NzkyLWI4NzYtNDllNy1iMmM1LTQ2NDY4NjI0MTk5ZSJ9.2r7f-SZJS2U8Zafqyl7oUYPfFGilDJemVwImPuIHxd0"
}
  • PUT 请求
jmilkfan@JmilkFan-Devstack:/opt/JmilkFan-s-Blog$ curl -X PUT -d "title=Just Test PUT" -d "text=Hello Guys" -d "tags=Python" -d "tags=Flask" -d "token=eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ4MzM2MjExNywiaWF0IjoxNDgzMzYxNTE3fQ.eyJpZCI6IjY1Y2I5NzkyLWI4NzYtNDllNy1iMmM1LTQ2NDY4NjI0MTk5ZSJ9.2r7f-SZJS2U8Zafqyl7oUYPfFGilDJemVwImPuIHxd0" http://localhost:8089/api/posts/1746b650-bcab-436b-82ab-7411e252b576
"1746b650-bcab-436b-82ab-7411e252b576"
  • 结果
mysql> select * from posts where id='1746b650-bcab-436b-82ab-7411e252b576';
+--------------------------------------+---------------+------------+--------------+--------------------------------------+
| id                                   | title         | text       | publish_date | user_id                              |
+--------------------------------------+---------------+------------+--------------+--------------------------------------+
| 1746b650-bcab-436b-82ab-7411e252b576 | Just Test PUT | Hello Guys | NULL         | 65cb9792-b876-49e7-b2c5-46468624199e |
+--------------------------------------+---------------+------------+--------------+--------------------------------------+
1 row in set (0.00 sec)

删除一条记录

jmilkfan@JmilkFan-Devstack:/opt/JmilkFan-s-Blog$ curl -X DELETE -d "token=eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ4MzM2MjkzMywiaWF0IjoxNDgzMzYyMzMzfQ.eyJpZCI6IjY1Y2I5NzkyLWI4NzYtNDllNy1iMmM1LTQ2NDY4NjI0MTk5ZSJ9.B8ISY5Fb6AD_PyrJxNVQNYuxXUMrEioB-rlhtyvYcxU" http://localhost:8089/api/posts/1746b650-bcab-436b-82ab-7411e252b576
  • 结果
mysql> select * from posts where id='1746b650-bcab-436b-82ab-7411e252b576';
Empty set (0.00 sec)