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时应该注意其必须的几个支持 ...
随机推荐
- ACM International Collegiate Programming Contest, Egyptian Collegiate Programming Contest (ECPC 2015)
A.Arcade Game(康拓展开) 题意: 给出一个每个数位都不同的数n,进行一场游戏.每次游戏将n个数的每个数位重组.如果重组后的数比原来的数大则继续游戏,否则算输.如果重组后的数是最大的数则算 ...
- NOIP2012 洛谷P1084 疫情控制
Description: H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情 ...
- codeforces 1060 A
https://codeforces.com/contest/1060/problem/A 题意:电话号码是以8开头的11位数,给你n 个数问最多可以有多少个电话号码 题解:min(8的个数,n/11 ...
- x:Class, x:Key
x:Class: 用来创建一个partial的class, 比如默认生成的x:Class="MyTest.MainWindow", 会自动生成一个MainWindow的partia ...
- WebComponents四大天王教程
Shadow Dom: http://www.html5rocks.com/zh/tutorials/webcomponents/shadowdom/ http://www.html5rocks.co ...
- [转载]超赞!32款扁平化Photoshop PSD UI工具包(下)
32款扁平化风格的UI工具包第二弹!上篇为大家分享了16款风格各异的UI Kits,下篇继续为大家呈上16款精美的UI工具包,全部都有Photoshop PSD文件可以下载哦,喜欢就赶紧收藏吧! 17 ...
- 【洛谷 P1651】 塔 (差值DP)
题目链接 题意:\(n\)个木块放到两个塔里,每个木块可放可不放,使得两塔高度相同且高度最大,求最大高度. 这个差值\(DP\)的思维难度还是很大的,没想出来,我就打了一个\(dfs\)骗了好像\(2 ...
- ZOJ1003 Crashing Balloon
Crashing Balloon Time Limit: 2 Seconds Memory Limit: 65536 KB On every June 1st, the Children's ...
- 【bzoj2086】Blocks
在洛谷上点了个Splay的tag想玩玩,结果看到这题…… #include<bits/stdc++.h> #define N 1000005 using namespace std; ty ...
- vijos P1051 送给圣诞夜的极光
调了好久... #include <cstdio> #include <queue> using namespace std; char a[110*110]; /****** ...