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时应该注意其必须的几个支持 ...
随机推荐
- [洛谷P1951]收费站_NOI导刊2009提高(2)
题目大意:有一张$n$个点$m$条边的图,每个点有一个权值$w_i$,有边权,询问从$S$到$T$的路径中,边权和小于$s$,且$\max\limits_{路径经过k}\{w_i\}$最小,输出这个最 ...
- 导致SQL执行慢的原因
索引对大数据的查询速度的提升是非常大的,Explain可以帮你分析SQL语句是否用到相关索引. 索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左 ...
- Codeforces Round #520 (Div. 2) A. A Prank
A. A Prank time limit per test 1 second memory limit per test 256 megabytes 题目链接:https://codefo ...
- 类名.class 类名.this 详解
我们知道在java中,一个类在被加载的时候虚拟机就会自动的生成一个这个类的一个Class类型的“类对象”,每个类都对应着一个这样的类对象,通过这个Class类型的类对象,我们就能够使用“内省与反射”机 ...
- Nginx support TCP Load balance
1. Install nginx package 2. edit nginx configuration file [root@ip- nginx]# more nginx.conf user ngi ...
- 固定width但是有间隔
<!DOCTYPE > <html> <head> <title></title> <meta name="name&quo ...
- uva 11427
题目大意:每天晚上你都玩纸牌,如果第一次赢了就高高兴兴地去睡觉:如果输了就接着玩,假设每盘游戏获胜的的概率都是p,且各盘游戏相互独立.你是一个固执的完美主义者,因此会一直玩到当晚获胜局数的比例严格大于 ...
- 动态规划:LCIS
先给出状态转移方程: 定义状态 F[i][j]表示以a串的前i个整数与b串的前j个整数且以b[j]为结尾构成的LCIS的长度 状态转移方程: ①F[i][j] = F[i-][j] (a[i] != ...
- rest service技术选型
MySql workbench下载 http://dev.mysql.com/downloads/workbench/ 最好的8个 Java RESTful 框架 http://colobu.com/ ...
- CTSC游记
CTSC游记 day 0 到达帝都. 复习板子 day 1 第一题傻逼题啊 第二题第三题写个暴力 好了120稳了 出来一看第一题基数排序炸了? 51+10+10崩盘 day 2 答辩有意思啊 王选怎么 ...