23、Flask实战第23天:Flask-Restful
Restful API规范
restful api是用于前端和后台进行通信的一套规范。使用这个规范可以让前后端开发变得更加轻松。
协议
采用http或者https
数据传输格式
数据之间传输的格式应该都使用json,而不是xml
url链接
url链接中,不能有动词,只能有名词。并且对于一些名词,如果出现复数,那么应该在后面加s
比如: 获取文章列表,应该使用/articles/, 而不应该使用/get_article/
HTTP请求方法
GET: 从服务器上获取资源 (常用)
POST:在服务器上新创建一个资源 (常用)
PUT:在服务器上更新资源。(客户端提供所有改变后的数据)
PATCH:在服务器上更新资源。(客户端只提供需要改变的属性)
DELETE: 从服务器上删除资源
状态码
状态码 | 原生描述 | 描述 |
200 | OK | 服务器成功响应客户端的请求 |
400 | INVALID REQUEST | 用户发出的请求有错误,服务器没有进行新建或修改数据的操作 |
401 | Unauthorized | 用户没有权限访问这个请求 |
403 | Forbidden | 因为某些原因禁止访问这个请求 |
404 | NOT FOUND | 用户发送的请求的url不存在 |
406 | NOT Accept | 用户请求不被服务器接收(比如服务器期望客户端发送某个字段,但没有发送) |
500 | Internal server error | 服务器内部错误,比如出现了bug |
Flask-Restful插件的基本使用
安装flask-restful插件
pip install flask-restful
定义Restful视图
如果使用flask-restful,那么定义视图函数的时候,就要继承自flask_restful.Resource类,然后再根据当前请求的method来定义相应的方法。比如期望客户端使用get方法发送请求,那么就定义一个get方法,期望客户端使用post方法发送请求,就定义一个post方法。类似于MethodView.
因为我们只定义了post方法,如果直接用浏览器去访问http://127.0.0.1:5000/login/(get方法),得不到我们想要的结果
这个时候我们就可以用一些测试工具,我这里使用的是Insomnia,同类的软件还有postman
url中也可以传递参数
url也可以是多个
参数验证
Flask-Restful插件提供了类似WTForm来验证提交的数据是否合法的包,叫做reqparse。以下是基本用法
parser = reqparse.RequestParser()
parser.add_argument('username', type=str, required=True, help='用户名验证错误')
args = parser.parse_args()
add_argument可以指定这个字段的名字,这个字段的数据类型等
default:默认值,如果这个参数没有值,那么将使用这个参数指定的值。
required:是否必须。默认为False,如果设置为True,那么这个参数就必须提交上来。
type:这个参数的数据类型,如果指定,那么将使用指定的数据类型来强制转换提交上来的值。
choices:选项。提交上来的值只有满足这个选项中的值才符合验证通过,否则验证不通过。
help:错误信息。如果验证失败后,将会使用这个参数指定的值作为错误信息。
trim:是否要去掉前后的空格。
其中的type,可以使用python自带的一些数据类型,也可以使用flask_restful.inputs下的一些特定的数据类型来强制转换。比如一些常用的:
url:会判断这个参数的值是否是一个url,如果不是,那么就会抛出异常。
regex:正则表达式。
date:将这个字符串转换为datetime.date数据类型。如果转换不成功,则会抛出一个异常。
操作演示
因为username字段添加了参数required=True,为必填项,因此如果客户端不传此字段,就会提示错误,这个错误提示就是我们自定的help--->"用户名验证错误"
...
from flask_restful import Api, Resource, reqparse, inputs app = Flask(__name__)
app.config.from_object(config)
api = Api(app) class RegisterView(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('username', type=str, required=True, help='用户名字段验证错误')
parser.add_argument('birthday', type=inputs.date, required=True, help='生日字段验证错误')
parser.add_argument('gender', type=str, choices=('male', 'female'), help='性别字段验证错误')
parser.add_argument('money', type=int, trim=True, default=0, help='金额字段验证错误')
parser.add_argument('phone', type=inputs.regex(r'1[3458]\d{9}'), help='手机字段验证错误')
parser.add_argument('blog', type=inputs.url, help='博客地址字段验证错误')
args = parser.parse_args()
print(args)
return 'success' api.add_resource(RegisterView, '/register/', endpoint='register')
...
Flask-Restful标准化返回参数
对于一个视图函数,我们可以指定好一些参数用于返回,在规范中要求:即使这个参数没有值也应该返回,返回一个None回去
...
from flask_restful import Api, Resource, fields, marshal_with api = Api(app) class ArticleView(Resource):
resource_field = { #先定义好返回哪些参数
'name': fields.String, #参数的数据类型
'age': fields.String,
'school': fields.String
} @marshal_with(resource_field) #利用marshal_with装饰器传入定义好的返回参数
def get(self):
return {} 就算这里返回个空字典,也会把定义好的参数返回 api.add_resource(ArticleView, '/article/', endpoint='article')
...
class ArticleView(Resource):
resource_field = {
'name': fields.String,
'age': fields.String,
'school': fields.String
} @marshal_with(resource_field)
def get(self):
return {'name': 'heboan', 'age': 18} ...
当使用ORM模型或者自定义的的模型的时候,它会自动的获取模型中相应的字段,生成json数据,然后返回给客户端
class ProfileView(Resource):
resource_fields = {
'username': fields.String,
'age': fields.Integer,
'school': fields.String
} @marshal_with(resource_fields)
def get(self,user_id):
user = User.query.get(user_id)
return user
在get方法中,返回user的时候,flask_restful会自动的读取user模型上的username, age以及school属性。组装成一个json格式的字符串返回给客户端
重名属性
如果我们想把面向公众的字段名称不用与内部的属性名。使用attribute可以配置这种属性,比如现在想要返回user.school中的值,但是在返回给外面的时候,想以education返回回去,那么可以这样写:
resource_fields = {
'education': fields.String(attribute='school')
}
默认值
在返回一些字段的时候,有时候可能没有值,那么这时候可以在指定fields的时候给定一个默认值,示例代码如下:
resource_fields = {
'age': fields.Integer(default=18)
}
复杂的结构
有时候想要在返回的数据格式中,形成比较复杂的结构。那么可以使用一些特殊的字段来实现。比如要在一个字段中放置一个列表,那么可以使用fields.List,比如在一个字段下面又是一个字典,那么可以使用fields.Nested。以下将讲解下复杂结构的用法:
定义数据库结构:
user表,article表,tag表, 因为article与tag是多对多的关系,因此需要一个中间表来关联article_tag
from exts import db class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(50), nullable=False) class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(50), nullable=False)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id')) author = db.relationship('User', backref='articles')
tags = db.relationship('Tag', secondary='article_tag') class Tag(db.Model):
__tablename__ = 'tag'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False) article_tag = db.Table(
'article_tag',
db.Column('article_id', db.Integer, db.ForeignKey('article.id')),
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
)
models
插入测试数据
...
from models import User, Article, Tag @app.route('/')
def index():
user = User(username='heboan')
tag_1 = Tag(name='Linux')
tag_2 = Tag(name='Python')
article = Article(title='python自动化运维', content='Life is short, I use python...') article.tags.append(tag_1)
article.tags.append(tag_2)
article.author = user db.session.add(article)
db.session.commit()
return '数据插入成功!'
视图
当我们全部使用field.String
class ArticleView(Resource):
resource_fields = {
'title':fields.String,
'content': fields.String,
'author':fields.String,
'tags':fields.String
} @marshal_with(resource_fields)
def get(self):
article = db.session.query(Article).get(1)
return article api.add_resource(ArticleView, '/article/', endpoint='article')
使用field.Nested、field.List
class ArticleView(Resource):
resource_fields = {
'title':fields.String,
'content': fields.String,
'author':fields.Nested({ #字典里面嵌套字典使用field.Nested
'username': fields.String
}),
'tags':fields.List(fields.Nested({ #tags是列表,使用field_List类型然后嵌套field.Nested
'id': fields.Integer,
'name': fields.String
}))
} @marshal_with(resource_fields)
def get(self):
article = db.session.query(Article).get(1)
print(article.title)
return article api.add_resource(ArticleView, '/article/', endpoint='article')
在蓝图使用使用Flask-Restful
新建一个articles.py
from flask import Blueprint
from flask_restful import Api, Resource, fields, marshal_with
from exts import db
from models import Article article_bp = Blueprint('article', __name__, url_prefix='/article')
api = Api(article_bp) #这里使用article_bp了 class ArticleView(Resource):
resource_fields = {
'title':fields.String,
'content': fields.String,
'author':fields.Nested({
'username': fields.String
}),
'tags':fields.List(fields.Nested({
'id': fields.Integer,
'name': fields.String
}))
} @marshal_with(resource_fields)
def get(self):
article = db.session.query(Article).get(1)
print(article.title)
return article api.add_resource(ArticleView, '/1/', endpoint='article')
主程序注册此蓝图
from article import article_bp
... app.register_blueprint(article_bp)
Flask-Restful渲染模板
先看看直接渲染模板是什么效果
class HelloView(Resource):
def get(self):
return render_template('hello.html') api.add_resource(HelloView, '/hello/', endpoint='hello')
可以发现这样渲染出来的页面并不是我们想要的。要想使用Flask-Restful渲染页面还需要定义一个out_html函数
@api.representation('text/html')
def out_html(data, code, headers):
resp = make_response(data)
return resp class HelloView(Resource):
def get(self):
return render_template('hello.html') api.add_resource(HelloView, '/hello/', endpoint='hello')
其中那个data就是页面的内容
23、Flask实战第23天:Flask-Restful的更多相关文章
- Flask实战-留言板-安装虚拟环境、使用包组织代码
Flask实战 留言板 创建项目目录messageboard,从GreyLi的代码中把Pipfile和Pipfile.lock文件拷贝过来,这两个文件中定义了虚拟环境中需要安装的包的信息和位置,进入m ...
- 1、Flask实战第1天:第一个Flask程序
Flask是流行的python web框架...(* ̄︶ ̄) 零基础到企业级论坛实战,人生苦短,我用python,开启FLask之旅吧... 安装开发环境 下载Python win版安装包 双击运行, ...
- 使用Flask设计带认证token的RESTful API接口
大数据时代 Just a record. 使用Flask设计带认证token的RESTful API接口[翻译] 上一篇文章, 使用python的Flask实现一个RESTful API服务器端 简 ...
- [易学易懂系列|rustlang语言|零基础|快速入门|(23)|实战1:猜数字游戏]
[易学易懂系列|rustlang语言|零基础|快速入门|(23)|实战1:猜数字游戏] 项目实战 实战1:猜数字游戏 我们今天来来开始简单的项目实战. 第一个简单项目是猜数字游戏. 简单来说,系统给了 ...
- Flask从入门到精通之flask安装
使用虚拟环境 安装Flask最简单的方式是使用虚拟环境,虚拟环境是python解释器的一个私有副本,在这个环境中你可以安装私有包,而且不会影响系统中安装的全局的Python解释器.虚拟环境非常有用,可 ...
- Python接口测试实战5(下) - RESTful、Web Service及Mock Server
如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...
- Flask框架(一)—— Flask简介
Flask框架(一)—— Flask简介 目录 Flask框架介绍 一.Flask简介 二.flask安装与使用 1.安装 2.使用 3.简单案例——flask实现用户登录 Flask框架介绍 一.F ...
- flask tutorial => make a blog :) flask 搭建博客系统从零开始!
please follow the tutorial from the official site :) http://flask.pocoo.org/docs/ You could download ...
- 【Flask】微型web框架flask大概介绍
Flask Flask是一个基于python的,微型web框架.之所以被称为微型是因为其核心非常简单,同时具有很强的扩展能力.它几乎不给使用者做任何技术决定. 安装flask时应该注意其必须的几个支持 ...
随机推荐
- MySQL自增属性auto_increment_increment和auto_increment_offset
MySQL的系统变量或会话变量auto_increment_increment(自增步长)和auto_increment_offset(自增偏移量)控制着数据表的自增列ID. mysql> sh ...
- Android 多线程: 完全解析线程池ThreadPool原理&使用
目录 1. 简介 2. 工作原理 2.1 核心参数 线程池中有6个核心参数,具体如下 上述6个参数的配置 决定了 线程池的功能,具体设置时机 = 创建 线程池类对象时 传入 ThreadPoolExe ...
- Java的Properties使用及格式定义
java.util.Properties extends Hashtable<Object,Object> 方便读取 键值对 格式的文本资源工具 常用方法一览 初始化对象 new Prop ...
- [Usaco2005 Dec]Cleaning Shifts 清理牛棚 (DP优化/线段树)
[Usaco2005 Dec] Cleaning Shifts 清理牛棚 题目描述 Farmer John's cows, pampered since birth, have reached new ...
- 前端面试:什么是css reset
HTML标签在浏览器中都有默认的样式,不同的浏览器的默认样式之间存在差别.例如ul默认带有缩进样式,在IE下,它的缩进是由margin实现的,而在Firefox下却是由padding实现的.开发时浏览 ...
- java+ssh+eclipse开发过程问题记录
原文 http://www.sdfengxi.com/?p=408 最近在忙着的项目是基于cloudstack平台的管理平台,因为CloudStack使用java开发,管理机上已部署好rhel+t ...
- javascript学习教程
我来班门弄斧一下吧,把我JavaScript学习过程中常去的一些网站分享给大家: =========================增加================================ ...
- salt-api的使用
curl -k https://192.168.74.129:8006/ -H "Accept: application/x-yaml" -H "X-Auth-Token ...
- 【bzoj3510】首都 LCT维护子树信息(+启发式合并)
题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...
- 【BZOJ】1799: [Ahoi2009]self 同类分布
[题意]给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数.1 ≤ a ≤ b ≤ 10^18 [算法]数位DP [题解] 感觉这种方法很暴力啊. 枚举数位和1~162(不能枚举0,不然会模 ...