Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog

目录

前文列表

用 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 设计 RESTful APIs

快速入门 — Flask-RESTful 0.3.1 documentation

Python爬虫常用之HtmlParser

构建 RESTful Flask API

为什么要构建 RESTful API ?

对于一个 blog application 而言, 其实完全可以不用到 restful api 也能满足日常所需. 加入 restful api 的唯一目标就是加强该项目的可扩展性, 为后期所要实现的诸如: 博客迁移/数据备份/功能扩展 提供统一且可靠的接口.

定义资源路由

首先我们要有一个大概的需求, 如果希望通过 HTTP 请求来完成对服务端资源的操作, 我们需要解决那些问题?

1. 首先要定位到该资源

2. 告诉服务端我要对该资源做那种操作

3. 前提还可能需要满足身份鉴权(这个需求, 我们后期再实现)

  • 安装 Flask-RESTful
pip install Flask-Restful
pip freeze > requirements.txt
  • 初始化 restful_api 对象

    vim jmilkfansblog/extensions.py
from flask.ext.restful import Api
... #### Create the Flask-Restful's instance
restful_api = Api()
  • 实现 PostApi 资源类

    我们将 posts 博客文章定义为一类资源, 只有定义了资源并且对外公开后, 才能被外部所调用.

    vim jmilkfansblog/controllers/flask_restful/posts.py
from flask.ext.restful import Resource

class PostApi(Resource):
"""Restful API of posts resource.""" def get(self, post_id=None):
"""Can be execute when receive HTTP Method `GET`.
Will be return the Dict object as post_fields.
"""
return {'hello': 'world'}

NOTE 1: jmilkfansblog/controllers/flask_restful 会作为一个包, 所以要记得创建 __init__.py 文件, 否则无法作为导入路径.

NOTE 2: 每个 REST 资源类都需要继承 flask_restful 的 Resource 类. 其所有的子类都可以通过定义同名实例函数来将该函数绑定到 HTTP Methods 中. EG. GET <==> get(), 放接受定位到资源的 HTTP GET 方法时, 就会执行该资源类的实例函数 get() .

  • 将 restful_api 对象注册到 app 对象中

    vim jmilkfansblog/__init__.py
from jmilkfansblog.extensions import restful_api
from jmilkfansblog.controllers.flask_restful.posts import PostApi
... def create_app(object_name):
...
#### Init the Flask-Restful via app object
# Define the route of restful_api
restful_api.add_resource(
PostApi,
'/api/posts')
restful_api.init_app(app)

NOTE 1: 在 restful_api.add_resource() 指定了资源类 PostApi 所对应的资源名称为 posts, 访问路由为 /api/posts, 这样才完成了对一个资源的完整定义.

NOTE 2: 同时再结合 PostApi 中的 get() 会自动的适配到 HTTP GET 方法, 这样就解决了我们之前所提出的 2 个问题.

现在我们引入一个新的问题, 通过上述定义的 get() 方法我们基本可以获取到数据库 posts 表中的所有记录(当然现在还没有连接数据库操作), 那么如果我只需要获取其中的某一条指定的记录呢?

这里需要在请求中指定 id 来完成单一的定位, 或者也可以传递一个 filters 来过滤若干条满足要求的数据记录.

  • 为资源 posts 添加多条路由

    vim jmilkfansblog/__init__.py
def create_app(object_name):
...
#### Init the Flask-Restful via app object
# Define the route of restful_api
restful_api.add_resource(
PostApi,
'/api/posts',
'/api/posts/<string:post_id>',
endpoint='restful_api_post')

NOTE: add_resource() 允许为同一个资源类绑定多条路由, '/api/posts/<string:post_id>' 表示可以访问 posts 这一类资源中某一个 post_id 一致的资源对象.

  • 为 get() 方法添加 post_id 形参数

    vim jmilkfansblog/controllers/flask_restful/posts.py
class PostApi(Resource):
"""Restful API of posts resource.""" def get(self, post_id=None):
"""Can be execute when receive HTTP Method `GET`.
Will be return the Dict object as post_fields.
""" if post_id:
return {'post_id': post_id}
return {'hello': 'world'}

格式化输出

在上一篇博文中提到, REST 约束要求我们使用一致的数据包装形式来进行响应, 所以我们需要实现一致的格式化功能. 本项目使用最常见的 JSON 格式.

  • Flask-Restful 的格式化输出, 首先需要定义出一个类似模板的 Dict 类型对象

    其 keys 是资源对应的 Model 对象所拥有且需要输出的字段名, values 则声明了该字段的值以何种类型转换并输出. 然后把该字典模板传给装饰器 @marshal_with 并装饰到所有资源类中需要返回数据到客户端的实例方法中. 如此之后,实例方法在返回数据之前都会按照该模板将数据进行格式化转换.

    注意: 字典模板的 keys 最好与 models 模块中定义的字段名相同, 否则无法自动完成字典模板与 Model 对象的匹配.

    vim jmilkfansblog/controllers/flask_restful/posts.py
from flask.ext.restful import Resource, fields, marshal_with
from jmilkfansblog.controllers.flask_restful import fields as jf_fields ... # String format output of tag
nested_tag_fields = {
'id': fields.String(),
'name': fields.String()} # String format output of post
post_fields = {
'author': fields.String(attribute=lambda x: x.user.username),
'title': fields.String(),
'text': jf_fields.HTMLField(),
'tags': fields.List(fields.Nested(nested_tag_fields)),
'publish_date': fields.DateTime(dt_format='iso8601')} class PostApi(Resource):
"""Restful API of posts resource.""" @marshal_with(post_fields)
def get(self, post_id=None):
"""Can be execute when receive HTTP Method `GET`.
Will be return the Dict object as post_fields.
""" if post_id:
return {'post_id': post_id}
return {'hello': 'world'}

NOTE 1: 这里需要使用到 flask_restful.fields, 其提供了绝大多数常用的格式类型定义, 具体格式类型列表可以查看官方文档. 当然, 我们也可以自定义一些格式类型, 例如 jf_fields.HTMLField()

NOTE 2: tags 和 author 字段并不存在与 posts 表中, 返回该字段是为了遵守 REST 的约束之一, RESTful API 返回的数据应该尽量满足客户端的需求. 所以我们一般会将表与表之前含有关联关系的字段都一同返回. 格式类型 List 可以接受另外一个格式化输出字典模板对象. 类似于 字典内嵌套字典的格式.

  • 自定义 fields 类型

    因为 posts 表中的 text 字段内容是一系列的 HTML 字符串(由 CKEditor 产生), 这些 HTML 字符串是不允许被 RESTful API 返回的, 因为要满足 REST 的约束之一, 服务端不参与用户界面表现层的业务逻辑(即 HTML 代码), 所以我们需要将该字段值中的 HTML 标签过滤掉.

    vim jmilkfansblog/controllers/flask_restful/fields.py
from HTMLParser import HTMLParser
from flask.ext.restful import fields class HTMLField(fields.Raw):
"""Define a new fields for filter the HTML tags string.""" def format(self, value):
return strip_tags(str(value)) class HTMLStripper(HTMLParser):
"""HTML Parser of Stripper.""" def __init__(self):
self.reset()
self.fed = [] def handle_data(self, data_object):
self.fed.append(data_object) def get_data(self):
return ''.join(self.fed) def strip_tags(html):
"""Filter the tags string of HTML for data object of Restful api.""" stripper = HTMLStripper()
stripper.feed(html) return stripper.get_data()

NOTE 1: 在 fields 模块中通过继承了 flask_restful.fields.Raw 类, 实现了新的格式类型 HTMLField .

NOTE 2: 使用 HTTPParser 来实现 HTML 解析, 重载 handle_data 方法用于将 HTML 标签之间的文本内容合并.

用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二的更多相关文章

  1. 用 Flask 来写个轻博客

    用 Flask 来写个轻博客 用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)V ...

  2. 用 Flask 来写个轻博客 (37) — 在 Github 上为第一阶段的版本打 Tag

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 第一阶段结语 打 Tag 前文列表 用 Flask 来写个轻博客 (1 ...

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

    目录 目录 前文列表 PUT 请求 DELETE 请求 测试 对一条已经存在的 posts 记录进行 update 操作 删除一条记录 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 ...

  4. 用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 POST 请求 身份认证 测试 前文列表 用 Flask 来写个轻博客 ...

  5. 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三

    目录 目录 前文列表 应用请求中的参数实现 API 分页 测试 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World! 用 F ...

  6. 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一

    目录 目录 前文列表 扩展阅读 RESTful API REST 原则 无状态原则 面向资源 RESTful API 的优势 REST 约束 前文列表 用 Flask 来写个轻博客 (1) - 创建项 ...

  7. 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 编写 FileSystem Admin 页面 Flask-A ...

  8. 用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 实现文章管理功能 实现效果 前文列表 用 Flask 来写个 ...

  9. 用 Flask 来写个轻博客 (29) — 使用 Flask-Admin 实现后台管理 SQLAlchemy

    目录 目录 前文列表 扩展阅读 Flask-Admin BaseView 基础管理页面 ModelView 实现效果 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写 ...

随机推荐

  1. 《JAVA设计模式》之装饰模式(Decorator)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述装饰(Decorator)模式的: 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替 ...

  2. Ubuntu12.04安装MariaDB并修改字符集为UTF-8

    其实按照MariaDB官网的步骤来安装MariaDB特别的简单,只要按照步骤来做,很容易就搞定了. 首先,到MariaDB官网: https://downloads.mariadb.org/maria ...

  3. memset 初始化数组 & 实现原理

    初始化数组可不必使用n重for循环. 原理 memset具有初始化数组的功能,能够初始化数组中的每一个值. 它是将数组中的每一个数的二进制的每一个字节初始化的. 比如初始化int类型的a数组:mems ...

  4. 道路模型--linear-parabolic model

    读过很多道路追踪的论文,经常都需要道路模型的建模.我不知道是不是因为自己太笨还是怎样,好多人建的模型我实在无法理解他的用意何在,而且我真的深刻怀疑他们那些模型的参数是不是真的可以求出来.就比如这篇文章 ...

  5. linux下创建svn仓库及用户

    1 Linux下创建svn仓库 1.1 启动SVN服务 svnserve -d -r  /SVNRootDirectry 其中SVNRootDirectry是你的SVN 根目录,例如192.85.1. ...

  6. RESET - 把一个运行时参数值恢复为缺省值

    SYNOPSIS RESET name RESET ALL DESCRIPTION 描述 RESET 将运行时参数恢复为缺省值. RESET 是下面语句的一个变种 SET parameter TO D ...

  7. 一、WebApi模型验证

    一.新建项目 选择空的项目webapi 查看启动端口 创建控制器 添加方法 public class VerifController : ApiController { public IHttpAct ...

  8. Polish orthography

    Computer encoding[edit] There are several different systems for encoding the Polish alphabet for com ...

  9. 洛谷4206/NOI2005T4 聪聪和可可 期望DP+记忆化搜索

    题意:给出n个点m条边的无向图,两个主角聪聪和可可开始分别在S点和T点.聪聪想吃掉可可,每次由匆匆先行动后来可可行动.聪聪的行动是选他到可可的最短路上的点走最多两步(如果最短路有几条就选编号最小的走) ...

  10. Python3.5-20190530-unittest模块

    >>> dir(unittest) #所有的属性和方法 ['BaseTestSuite', 'FunctionTestCase', 'SkipTest', 'TestCase', ' ...