<div id="post_detail">

flask插件系列之flask_restful设计API

前言

flask框架默认的路由和视图函数映射规则是通过在视图函数上直接添加路由装饰器来实现的,这使得路由和视图函数的对应关系变得清晰,但对于统一的API开发就变得不怎么美妙了,尤其是当路由接口足够多的时候,可读性会变差。flask_restful可以使我们像Django那样统一在一个地方设计所有的API规则。

flask_restful

安装

pip install flask_restful

初始化

# __init__.py
from flask import Flask, current_app app = Flask(name) app.config['SECRET_KEY'] = '123' # rest/init_.py

from flask import Blueprint

from flask_restful import Api # 创建蓝图

rest = Blueprint("rest", name)

flask_api = Api(app=rest)

all = ["rest","api"] # 加载蓝图所对应的视图上下文

from .api import * # 设计路由

flask_api.add_resource(ToDo1,'/restful')

flask_api.add_resource(Todo,"/restful1") # rest/api.py

from flask_restful import Resource, fields, marshal_with, reqparse

parser = reqparse.RequestParser() class ToDo1(Resource):

def get(self):

# 拷贝一个对象备用

new_parser = parser.copy()

# 添加请求参数和它的验证规则

new_parser.add_argument('n', type=int, help='Rate to charge for this resource,{error_msg}')

# 进行验证,得到通过验证后的字典或者抛出400错误

args = new_parser.parse_args(strict=True)

print(args)

return "OK"

说明:

  • Api类管理着视图函数的注册和相关资源,使用app或蓝图对象对其进行初始化;

  • 我们定义一个类继承Resource,通过方法名指定post、get等请求方式的处理逻辑;

  • 使用Api.add_resource方法设计api接口,指定路由和视图函数的映射关系;

  • 使用RequestParser对象对参数进行验证;

  • 核心的对象有Api和Resource,针对其一一分析;

APi对象分析

  • 初始化

针对需要使用restful风格的蓝图进行初始化。

test = Blueprint("test", __name__)
api = Api(app=test, prefix='/rest1') # prefix添加url的前缀,如果蓝图也有前缀则拼接
  • Api.add_resource

该方法对路由和视图函数进行设计设定。创建了RULE对象,并将其添加到Maps对象中,同时将resource添加到app的view_functions中;

# 参数
resource:视图类
urls:路由url,可以多个指向一个视图类
endpoint:视图函数的标志,默认用类名替代 api.add_resource(Todo,"/restful","/index", endpoint="restful")

请求数据验证

对于收到的每一个请求,如果它带了参数,后台是需要对参数进行验证的,这是一个十分枯燥的工作,RequestParser对象就是帮助我们对参数进行验证的,它可以实现验证方法对验证参数的解耦,是的代码结构趋向统一。

  • RequestParser
# 创建一个RequestParser,其会拦截request上下文,但是其内部存储的参数列表对所有的请求都是同一个,因此针对每个请求都需要一个新的对象
parser = reqparse.RequestParser() class ToDo1(Resource):

def get(self):

# 拷贝一个对象备用

new_parser = parser.copy()

# 向参数列表添加请求参数和它的验证规则,每个参数单独添加

new_parser.add_argument('n', type=int, help='Rate to charge for this resource,{error_msg}')

# 进行验证,得到通过验证后的字典或者抛出400错误

args = new_parser.parse_args(strict=True)

print(args)

return "OK"

# 使用 strict=True 调用 parse_args 能够确保当请求包含你的解析器中未定义的参数的时候会抛出一个异常。

  • RequestParser.add_argument

该方法其实是创建了一个Argument对象,其参数对应了Argument的初始化参数

def __init__(self, name, default=None, dest=None, required=False,
ignore=False, type=text_type, location=('json', 'values',),
choices=(), action='store', help=None, operators=('=',),
case_sensitive=True, store_missing=True, trim=False,
nullable=True):
self.name = name # 参数的名字
self.default = default # 如果没有该参数,其默认的值
self.dest = dest # name的别名,解析后该参数的键编程别名
self.required = required # 参数是否可以省略,设置为True时,这个参数是必须的
self.ignore = ignore # 是否忽略参数类型转换失败的情况,默认不忽略
self.location = location # 从请求对象中获取的参数类型,默认从values和json中解析值,但是可以指定'args','form','json',''headers','files'等解析;或指定列表['args','form'],优先解析列表末尾的值
self.type = type # 转换的参数类型,默认转换成str,失败就报错
self.choices = choices # 参数的值的有限集合,不在其中就报错,如[1,2,3]
self.action = action # 如果要接受一个键有多个值的话,可以传入 action='append', 默认是禁止的
self.help = help # 参数无效时可以返回的信息,默认返回错误信息
self.case_sensitive = case_sensitive # 是否区分大小写,默认所有大写转换成小写
self.operators = operators
self.store_missing = store_missing # 缺少参数时是否加默认的值
self.trim = trim # 是否去除参数周围的空白
self.nullable = nullable # 是否允许参数使用空值 new_parser.add_argument('n', type=int, help='msgerr',location=('args',), required=True) # 从参数中获取n,该参数是必须的

  • RequestParser.replace_argument和RequestParser.remove_argument

覆盖解析规则和删除解析规则,主要用在当多个api有相同的解析参数时,可以设置共享参数解析;

parser = RequestParser()
parser.add_argument('foo', type=int) parser_copy = parser.copy()

parser_copy.add_argument('bar', type=int) parser_copy.replace_argument('foo', type=str, required=True, location='json')

验证方法

Argument对象的type参数指定了参数的验证方法,除了我们python常用的数据类型外,inputs模块预定义了一些验证方法供我们验证。

  • input模块
parser_copy.add_argument('bar', type=url) # 验证是否符合url格式
parser_copy.add_argument('bar', type=inputs.regex('^[0-9]+$')) # 自定义正则验证
date:转换成datatime.data对象;
natural:转换类型为自然数;
positive:转换类型为正整数
int_range:输入整数的范围,设置最大最小值
boolean:限制必须为布尔类型;
  • 自定义验证方法

input模块提供的方法也是不够用的。很多时候我们需要自定义验证方法:

def ver_num(value, name):name表示参数名
if value % 2 == 0:
raise ValueError("Value is not odd")
return value
parser_copy.add_argument('bar', type=ver_num) # 验证是调用:ver_num("xxx","bar") # 方法必须有两个参数,第一个value表示参数的值,name表示参数的名字,

# 如果验证不通过,我们就抛出一个ValueError错误。

  • RequestParser.parse_args

当调用parse_args时就会按添加时的顺序依次验证请求参数,如果有验证不通过的参数,调用flask.abort(400);

如果设置了strict=True,请求包含解析器中未定义的参数也会抛出400状态码。

parse_args
#参数:
req:请求上下文,默认使用flask.request
strict:请求是否可以包含解析器中未定义的参数,默认false,即可以。

实际使用时如果我们想改变抛出异常的错误处理就最好捕捉一下异常:

class ToDo1(Resource):
try:
new_parser = parser.copy()
new_parser.add_argument('n', type=int, help='Rate to charge for this resource,{error_msg}')
args = new_parser.parse_args(strict=True)
except HTTPException as e:
do somthing...
raise e
return "OK"

小结

  • 对于RequestParser来说,其主要的功能对请求的参数进行验证,验证通过反馈参数字典,否则抛出400异常;

  • 我们可以设置自定义的验证类型来验证额外的需求;

格式化返回数据

通过marshal_with装饰器,我们可以对视图函数返回的数据进行格式化,使得呈现给前端的数据符合我们预期要返回的数据格式,而不需要去手动使用代码转化;

class Todo(Resource):
@marshal_with({'data':fields.String}, envelope='resource')
def get(self, **kwargs):
return {'data':'xiao'} # 前端数据

{"resource": {"data": "xiao"}} # 参数

fields:数据规则;

envelope:数据的键,如果定义了该值,数据就以该值为键返回。

使用方式

  • 定义想要返回的数据格式,可以是复杂的嵌套结构
resource_dict = {"status_code": fields.Integer,
"message": {"count": fields.Integer, "newcount": fields.Integer}}

但是我们视图函数的返回值可以是扁平结构:

resource_fields = {"status_code":fields.Integer,
"data":{"count": fields.Integer, "newcount": fields.List(fields.Integer)}}, @app.route('/')

@marshal_with(resource_fields,

envelope='message')

def index(self):

return {"status_code":200, "count":10, "newcount": [5,6]}

marshal_with会将你返回的数据和预定义的数据进行比较,存在的就填充,不存在就用None替代,用envelope为键将结果包裹;装饰过后视图函数的返回结果是OrderedDict对象。

  • 自定义返回的数据类型

restful模块默认对前端返回的是json格式的字符串数据,所有的Api都只支持json,即所有视图返回的数据都会默认尝试转化成json格式,不成功就会报错。我们可以指定APi默认输出的格式,如html,csv,json等;

# 设置输出html格式,所有视图返回的数据都会默认尝试转化成text/html格式
rest_api = Api(app)
@rest_api.representation('text/html')
def output_html(data, code, headers=None):
resp = make_response(data, code)
resp.headers.extend(headers or {})
return resp
#或者这样写:
rest_api.representations = OrdereDict({'text/html':output_html}) # 同理如果想设置其他格式的处理函数

@rest_api.representation('application/json')

def output_json(data, code, headers=None):

pass

@api.representation('text/csv')

def output_csv(data, code, headers=None):

pass # 或者

rest_api.representations = OrdereDict({'application/json':output_json})

rest_api.representations = OrdereDict({'text/csv':output_csv})

fields模块

fields模块可以说是专为json数据交互准备的,被marshal_with装饰的视图函数必须返回字典对象,它定义了许多的针对视图函数对外的格式化处理方法。

resource_fields = {
'name': fields.String,
'address': fields.String,
'date_updated': fields.DateTime(dt_format='rfc822'),
}

相应的字段有:

"String":字符串,参数attribute指定别名,default指定默认值;

"FormattedString":格式化字符串,参数如"name{age}"这种形式

"Url":生成url,参数endpoint和url_for的参数类似,根据它找到对应的url,参数absolute=True则生成绝对url,参数scheme='https'则修改协议

"DateTime":转化日期的标准格式,如datetime.datetime(2018,11,23)--》"Fri, 23 Nov 2018 00:00:00 -0000"

"Float":小数;

"Integer":整形,默认为0;

"Arbitrary":任意精度的浮点数

"Nested":嵌套结构;

"List":列表类型,参数cls_or_instance指定列表元素的类型,如:List(String)

"Raw":基类,参数attribute指定别名,default指定默认值;

"Boolean":布尔值,返回True或False

"Fixed":固定精度的十进制数,参数decimals指定精度;

"Price":Fixed的引用;

  • 如果内置的字段不满足我们的要求,我们可以自定义:
class UrgentItem(fields.Raw):
def format(self, value):
return "big" if value == 1 else "small" # 只需要继承Raw并实现format函数即可

参考:

	</div>
<div class="postDesc">posted @ <span id="post-date">2018-09-26 22:30</span> <a href="https://www.cnblogs.com/cwp-bg/">天宇之游</a> 阅读(<span id="post_view_count">306</span>) 评论(<span id="post_comment_count">0</span>) <a href="https://i.cnblogs.com/EditPosts.aspx?postid=9687222" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(9687222);return false;">收藏</a></div>
</div>
<script src="//common.cnblogs.com/highlight/9.12.0/highlight.min.js"></script><script>markdown_highlight();</script><script type="text/javascript">var allowComments=true,cb_blogId=349326,cb_entryId=9687222,cb_blogApp=currentBlogApp,cb_blogUserGuid='585e0a6f-e112-e711-845c-ac853d9f53ac',cb_entryCreatedDate='2018/9/26 22:30:00';loadViewCount(cb_entryId);var cb_postType=1;var isMarkdown=true;</script>

发表评论

昵称:

评论内容:





不改了
退出
订阅评论

[Ctrl+Enter快捷键提交]

</div><!--end: forFlow -->
</div>
posted @
2019-04-01 16:07 
P_PlusUltra 
阅读(...) 
评论(...) 
编辑 
收藏

flask_restful(转载)的更多相关文章

  1. Crystal Clear Applied: The Seven Properties of Running an Agile Project (转载)

    作者Alistair Cockburn, Crystal Clear的7个成功要素,写得挺好. 敏捷方法的关注点,大家可以参考,太激动所以转载了. 原文:http://www.informit.com ...

  2. RTP与RTCP协议介绍(转载)

    RTSP发起/终结流媒体.RTP传输流媒体数据 .RTCP对RTP进行控制,同步.RTP中没有连接的概念,本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完 ...

  3. 《Walking the callstack(转载)》

    本文转载自:https://www.codeproject.com/articles/11132/walking-the-callstack Download demo project with so ...

  4. [转载]MVVM模式原理分析及实践

    没有找到很好的MVVM模式介绍文章,简单找了一篇,分享一下.MVVM实现了UI\UE设计师(Expression Blend 4设计界面)和软件工程师的合理分工,在SilverLight.WPF.Wi ...

  5. [转载]:STM32为什么必须先配置时钟再配置GPIO

    转载来源 :http://blog.csdn.net/fushiqianxun/article/details/7926442 [原创]:我来添两句,就是很多同学(包括我)之前搞低端单片机,到了stm ...

  6. [转载]从MyEclipse到IntelliJ IDEA-让你摆脱鼠标,全键盘操作

    从MyEclipse转战到IntelliJ IDEA的经历 注转载址:http://blog.csdn.net/luoweifu/article/details/13985835 我一个朋友写了一篇“ ...

  7. TCP同步与异步,长连接与短连接【转载】

    原文地址:TCP同步与异步,长连接与短连接作者:1984346023 [转载说明:http://zjj1211.blog.51cto.com/1812544/373896   这是今天看到的一篇讲到T ...

  8. 在CentOS 7/6.5/6.4 中安装Java JDK 8(转载)

    转载在CentOS 7/6.5/6.4 中安装Java JDK 8 首先,在你的服务器上运行一下更新. yum update 然后,在您的系统上搜索,任何版本的已安装的JDK组件. rpm -qa | ...

  9. 用C#实现MD5的加密(转载)

    方法一 首先,先简单介绍一下MD5 MD5的全称是message-digest algorithm 5(信息-摘要算法,在90年代初由mit laboratory for computer scien ...

随机推荐

  1. htaccess跨域

    目的:为了加快访问速度,减轻主站压力,把静态资源放到独立的服务器上,使用独立的域名 问题:浏览器为安全考虑,实施同源策略:ip/域名和端口必须相同 解决办法: 1.httpd.conf中,开启apac ...

  2. Golang 之 key-value LevelDB

    时常会在应用中用到数据库功能,象 Key-Value 性质的.直接搬个 Redis,Mysql嫌大,好在有 LevelDB,直接编进应用中. 有关什么是 LevelDB 以及 LevelDB 的特性, ...

  3. Photo3

    Story: 这是一个简朴的家,有用旧了的风扇,木制的桌子,桌子上放了未完成的功课,还有一只正在睡觉的猫.阳光从窗户照进来,微风轻轻的吹着.想象你是坐在窗边吹风的小女孩,你的眼睛正眺望着不远处的风景, ...

  4. webstorm最新破解方法

    方法来自 Rover12421 大神. 1.从官网下载WebStorm2016.1安装. 2.下载 破解补丁 并解压,记住路径 3.编辑WebStorm安装目录下 bin 文件夹中的 WebStorm ...

  5. composer 更新

    composer self-update --preview 清除缓存 composer clearcache

  6. charCodeAt方法以及Unicode中文汉字编码范围

    js的charCodeAt() 方法可返回指定位置的字符的 Unicode 编码.这个返回值是 0 - 65535 之间的整数. 在字符串 "Hello world!" 中,我们将 ...

  7. 使用word文档直接发表博客 8 )

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  8. Exception (2) Java Exception Handling

    The Java programming language uses exceptions to handle errors and other exceptional events.An excep ...

  9. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(9):通过XML装配Bean

    一.通过XML装配Bean 装配简易值 装配集合 命名空间装配(暂不测试) 二.测试例子 创建一个用户类:UserBean.java package com.xfwl.spring.assem; /* ...

  10. How To Start Building Spatially Aware Apps With Google’s Project Tango

    How To Start Building Spatially Aware Apps With Google’s Project Tango “Tango can enable a whole new ...