适用场景:一个系统的数据库数据,展现的平台有PC端、移动端、app端、ios端。
前端工程师:都遵循RESTful编程规范
后端工程师:都遵循RESTful编程规范
最终结果:开发效率高,便于管理
协议:用http或者https协议。
数据传输格式:数据传输的格式应该都用 json 格式。
url链接规则:
url链接中,不能有动词,只能有名词。
并且对于一些名词,如果出现复数,那么应该在后面加s。
比如:获取新闻列表,应该使用/news/
,而不应该使用/get_news/
HTTP请求方式:
GET:从服务器上获取资源。
POST:在服务器上新增或者修改一个资源。
PUT:在服务器上更新资源。(客户端提供所有改变后的数据)
PATCH:在服务器上更新资源。(客户端只提供需要改变的属性)
DELETE:从服务器上删除资源。
状态码 | 原因描述 | 描述 |
---|---|---|
200 | OK | 服务器成功响应客户端的请求。 |
400 | INVALID REQUEST | 用户发出的请求有错误,服务器没有进行新建或修改数据的操作 |
410 | INVALID REQUEST | 用户没有权限访问这个请求 |
403 | Forbidden | 因为某些原因禁止访问这个请求 |
404 | NOT FOUND | 用户请求的url不存在 |
406 | NOT Acceptable | 用户请求不被服务器接收(比如服务器期望客户端发送某个字段,但是没有发送)。 |
500 | NOT FOUND | 服务器内部错误,比如遇到bug |
1.介绍:
优势:
Flask-Restful是一个专门用来写restful api的一个插件。
使用它可以快速的集成restful api接口功能。
在系统的纯api的后台中,这个插件可以帮助我们节省很多时间。
缺点:
如果在普通的网站中,这个插件就没有优势了,因为在普通的网站开发中,是需要去渲染HTML代码的,
而Flask-Restful在每个请求中都是返回json格式的数据。
pip install flask-restful
基本使用:
定义Restful的类视图:
flask_restful
中导入Api
,来创建一个api
对象。Resource
类,然后在这个里面,使用你想要的请求方式来定义相应的方法,比如你想要将这个类视图只能采用post
请求,那么就定义一个post
方法。api.add_resource
来添加类视图与url
。from flask import Flask,url_for,render_template
from flask_restful import Api,Resource
app = Flask(__name__)
api = Api(app)
class LoginView(Resource):
def post(self):
return {"flag":"yes"}
def get(self):
return {"flag":"no"}
# api.add_resource(LoginView,'/login/')
api.add_resource(LoginView,'/login/','/login2/',endpoint="login")
with app.test_request_context():
# print(url_for('loginview'))
print(url_for('login'))
@app.route('/')
def hello_world():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
app.route
的方式。参数验证:(也叫参数解析) Flask-Restful插件提供了类似WTForms来验证提交的数据是否合法的包,叫做reqparse。
基本用法:(借助于测试工程师 常用的接口测试工具postman来检验)
from flask import Flask,url_for,render_template
from flask_restful import Api,Resource,reqparse,inputs
app = Flask(__name__)
api = Api(app)
class RegisterView(Resource):
def post(self):
#验证用户名
# 1.创建解析器对象
parser = reqparse.RequestParser()
# 2.利用解析器对象添加 需要验证的参数
parser.add_argument('uname',type=str,help='用户名验证错误!',required=True,trim=True)
# 3.利用解析器对象进行验证,若正确,直接返回验证后合格的参数值,若错误,抛异常信息给客户端
args = parser.parse_args()
print(args)
return {"tips":"注册成功"}
api.add_resource(RegisterView,'/register/')
@app.route('/')
def hello_world():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
add_argument
方法使用详解:add_argument方法可以指定这个字段的名字,这个字段的数据类型等,验证错误提示信息等,具体如下:
default:默认值,如果这个参数没有值,那么将使用这个参数指定的默认值。
required:是否必须。默认为False,如果设置为True,那么这个参数就必须提交上来。
type:这个参数的数据类型,如果指定,那么将使用指定的数据类型来强制转换提交上来的值。
choices:固定选项。提交上来的值只有满足这个选项中的值才符合验证通过,否则验证不通过。
help:错误信息。如果验证失败后,将会使用这个参数指定的值作为错误信息。
trim:是否要去掉前后的空格。
其中的type:
from flask import Flask,url_for,render_template
from flask_restful import Api,Resource,reqparse,inputs
app = Flask(__name__)
api = Api(app)
#Flask_RESTful功能之参数验证
class RegisterView(Resource):
def post(self):
#用户名 密码 年龄 性别 出生日期 号码 个人主页
# 1.创建解析器对象
parser = reqparse.RequestParser()
#2.利用解析器对象添加 需要验证的参数
parser.add_argument('uname',type=str,help='用户名验证错误!',required=True,trim=True)
parser.add_argument('pwd', type=str, help='密码验证错误!',default="123456")
parser.add_argument('age',type=int,help='年龄验证错误!')
parser.add_argument('gender',type=str,choices=['男','女','双性'])
parser.add_argument('birthday',type=inputs.date,help='生日字段验证错误!')
parser.add_argument('phone',type=inputs.regex(r'1[3578]\d{9}'))
parser.add_argument('phomepage',type=inputs.url,help='个人中心链接验证错误!')
#3.利用解析器对象进行验证,若正确,直接返回验证后合格的参数值,若错误,抛异常信息给客户端
args = parser.parse_args()
print(args)
return {"tips":"注册成功"}
api.add_resource(RegisterView,'/register/')
@app.route('/')
def hello_world():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
Flask_RESTful返回标准化参数:
flask_restful.marshal_with
装饰器。flask_restful
会自动的读取对象模型上的所有属性。代码演示:
from flask import Flask
from flask_restful import Api,Resource,fields,marshal_with
app = Flask(__name__)
api = Api(app)
# flask_restful返回标准化参数
class News(object):
def __init__(self,title,content):
self.title =title
self.content =content
news = News('能力强的体现','能屈能伸')
class NewsView(Resource):
resource_fields ={
'title': fields.String,
'content':fields.String
}
@marshal_with(resource_fields)
def get(self):
# restful规范中,要求,定义好了返回的参数个数 和 内容
# return {'title':"世界太大",'content':"可钱包太小"}
#好处01:体现规范化,即使content这个参数没有值,也应该返回,返回一个null回去
# return {'title':"世界太大"}
#好处02:体现规范化,还可以返回一个对象模型回去
return news
api.add_resource(NewsView,'/news/')
if __name__ == '__main__':
app.run(debug=True)
需求1:有的时候你对外给出的属性名和模型内部的属性名不相同时,可使用 attribute
可以配置这种映射。
比如想要返回模型对象user.username
的值,但是在返回给外面的时候,想以uname
返回去。
需求2:在返回某些字段的时候,有时候可能没有值,但想给一个值用以提示,那么这时候可以在指定 fields
的时候使用 default
指定默认值
from flask import Flask,url_for,render_template
from flask_restful import Api,Resource,reqparse,inputs,fields,marshal_with
app = Flask(__name__)
api = Api(app)
# flask_restful返回标准化参数强化
class User():
def __init__(self,username,age):
self.username=username
self.age=age
self.signature=None
class UserView(Resource):
resource_fields={
# 01.重命名属性
'uname':fields.String(attribute='username'),
'age':fields.Integer,
# 02.默认值
'signature':fields.String(default='此人很懒,什么也没写')
}
@marshal_with(resource_fields)
def get(self):
user = User('莫莫',18)
return user
api.add_resource(UserView,'/user/')
if __name__ == '__main__':
app.run(debug=True)
复杂的参数结构:大型的互联网项目中,返回的数据格式,是比较复杂的结构。如:小米商城,
https://www.mi.com/
https://a.huodong.mi.com/flashsale/getslideshow
总结,无非就是key对应的value又是一个json,或者key对应的是一个列表,列表中的每项都是json那么可以使用一些特殊的字段来实现。如在一个字段中放置一个列表,那么可以使用 fields.List
,如在一个字段下面又是一个字典,那么可以使用 fields.Nested
。
from flask import Flask,url_for,render_template
from flask_restful import Api,Resource,reqparse,inputs,fields,marshal_with
app = Flask(__name__)
api = Api(app)
# flask_restful返回标准化参数强化
# 复杂的参数结构
# 实体间关系有 1:1 1:n n:n(转为2个1:n)
# 新闻系统后台;用户;新闻;新闻标签
class User():
def __init__(self,id,uname,age):
self.id = id
self.uname = uname
self.age = age
def __repr__(self):
return "" .format(id=self.id, uname=self.uname,age=self.age)
class News():
def __init__(self,id,title,content):
self.id=id
self.title=title
self.content=content
#关系映射
self.author=None
self.tags=[]
def __repr__(self):
return "" \
.format(id=self.id, title=self.title,content=self.content,author=self.author,tags=self.tags)
class NewsTag():
def __init__(self,id,name):
self.id=id
self.name=name
def __repr__(self):
return '' .format(id =self.id , name=self.name)
def createData():
user = User(110,'莫莫',30)
tag1 = NewsTag(200,"要闻")
tag2 = NewsTag(210,"娱乐")
news =News(300,'吴京征服了世界上海拔最高的派出所','4月23日中午11点,吴京发了一条微博,配文“世界上海拔最高的派出所”,并@了另外一名演员张译。微博中有两张图片,第一张是吴京和张译两人坐在地上的合照,背后几个大字“中国边防”。第二张则是两人与派出所民警们的合照。 ')
news.author = user #绑定新闻作者
news.tags.append(tag1) #绑定新闻标签1
news.tags.append(tag2) #绑定新闻标签2
print(news)
return news
class NewsView2(Resource):
resource_fields={
'id':fields.Integer,
'title': fields.String,
'content': fields.String,
# 如在一个字段下面又是一个字典,那么可以使用fields.Nested({...})
'author': fields.Nested({
'id': fields.Integer,
'uname': fields.String,
'age':fields.Integer
}),
# 如要在一个字段中放置一个列表,那么可以使用fields.List(fields.Nested({...}))
'tags': fields.List(fields.Nested({
'id': fields.Integer,
'name': fields.String
}))
}
@marshal_with(resource_fields)
def get(self):
news = createData()
return news
api.add_resource(NewsView2,'/news2/')
if __name__ == '__main__':
app.run(debug=True)
app
对象了【蓝图 news.py 文件】
from flask import url_for,render_template,Blueprint,make_response,Response
from flask_restful import Api,Resource,reqparse,inputs,fields,marshal_with
import json
news_bp = Blueprint('news',__name__,url_prefix='/news')
api = Api(news_bp)
# 01.flask-restful结合蓝图使用
# 复杂的参数结构
# 实体间关系有 1:1 1:n n:n(转为2个1:n)
# 新闻系统后台 用户 新闻 新闻标签
class User():
def __init__(self,id,uname,age):
self.id = id
self.uname = uname
self.age = age
def __repr__(self):
return "" .format(id=self.id, uname=self.uname,age=self.age)
class News():
def __init__(self,id,title,content):
self.id=id
self.title=title
self.content=content
#关系映射
self.author=None
self.tags=[]
def __repr__(self):
return "" \
.format(id=self.id, title=self.title,content=self.content,author=self.author,tags=self.tags)
class NewsTag():
def __init__(self,id,name):
self.id=id
self.name=name
def __repr__(self):
return '' .format(id =self.id , name=self.name)
def createData():
user = User(110,'莫莫',30)
tag1 = NewsTag(200,"要闻")
tag2 = NewsTag(210,"娱乐")
news =News(300,'吴京征服了世界上海拔最高的派出所','4月23日中午11点,吴京发了一条微博,配文“世界上海拔最高的派出所”,并@了另外一名演员张译。微博中有两张图片,第一张是吴京和张译两人坐在地上的合照,背后几个大字“中国边防”。第二张则是两人与派出所民警们的合照。 ')
news.author = user #绑定新闻作者
news.tags.append(tag1) #绑定新闻标签1
news.tags.append(tag2) #绑定新闻标签2
print(news)
return news
class NewsView2(Resource):
resource_fields={
'id':fields.Integer,
'title': fields.String,
'content': fields.String,
#如在一个字段下面又是一个字典,那么可以使用fields.Nested({...})
'author': fields.Nested({
'id': fields.Integer,
'uname': fields.String,
'age':fields.Integer
}),
#如要在一个字段中放置一个列表,那么可以使用fields.List(fields.Nested({...}))
'tags': fields.List(fields.Nested({
'id': fields.Integer,
'name': fields.String
}))
}
@marshal_with(resource_fields)
def get(self):
news = createData()
return news
api.add_resource(NewsView2,'/news2/')
【app.py 文件】
from flask import Flask,url_for,render_template
from blueprints.news import news_bp
app = Flask(__name__)
app.register_blueprint(news_bp)
@app.route('/')
def hello_world():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
api.representation
这个装饰器来定义一个函数,在这个函数中,应该对html
代码进行一个封装,再返回。vfrom flask import url_for,render_template,Blueprint,make_response,Response
from flask_restful import Api,Resource,reqparse,inputs,fields,marshal_with
import json
news_bp = Blueprint('news',__name__,url_prefix='/news')
api = Api(news_bp)
# 02. 使用flask-restful渲染模版
class ListView(Resource):
def get(self):
return render_template('index.html')
api.add_resource(ListView,'/list/')
# 渲染模版经过修改后,能支持html和json
@api.representation('text/html')
def output_html(data,code,headers):
if isinstance(data,str):
# 在representation装饰的函数中,必须返回一个Response对象
# resp = make_response(data)
resp =Response(data)
return resp
else:
return Response(json.dumps(data),mimetype='application/json')
【34_flask_restful_demo.py】
from flask import Flask,url_for
from flask_restful import Api,Resource,reqparse,inputs,fields,marshal_with
from datetime import date
from blueprints.news import news_bp
app = Flask(__name__)
# api = Api(app) #此写法适用于 在当前文件中使用flask_restful写接口
# date(year=,month=,day=)
app.register_blueprint(news_bp)
@app.route('/')
def hello_world():
return 'Hello World!'
# Flask_RESTful的基本使用
# 定义一个类视图
# class LoginView(Resource):
# def get(self):
# return {"flag":'no'}
# def post(self):
# return {"flag":"yes"}
# #映射url
# # api.add_resource(LoginView,'/login/','/login2/')
# api.add_resource(LoginView,'/login/','/login2/',endpoint="login")
# with app.test_request_context():
# # print(url_for('loginview')) #如果不写endpoint,那么将会使用视图的名字的小写来作为endpoint。
# print(url_for('login')) #如果指定了endpoint,就必须使用endpoint的值来构建url
# Flask_RESTful功能之参数验证 基本用法
# class RegisterView(Resource):
# def post(self):
# #用户名 uname
# #1.创建一个解析器对象
# parse = reqparse.RequestParser()
# #2.利用解析器对象 添加需要验证的参数 并指定验证规则
# parse.add_argument('uname',type =str,help="用户名不符合规则!!",required=True,trim=True)
# #3.利用解析器对象 进行验证 若正确,直接返回验证后合格的参数值,若错误,抛异常信息给客户端
# args =parse.parse_args()
# #若验证成功后,需要插入数据库
# print(args)
# return {'tips':"注册成功"}
#
# api.add_resource(RegisterView,'/register/')
# Flask_RESTful功能之参数验证 更多用法
# class RegisterView(Resource):
# def post(self):
# #用户名 密码 年龄 性别 出生日期 号码 个人主页
# # 1.创建解析器对象
# parser = reqparse.RequestParser()
# #2.利用解析器对象添加 需要验证的参数
# parser.add_argument('uname',type=str,help='用户名验证错误!',required=True,trim=True)
# parser.add_argument('pwd', type=str, help='密码验证错误!',default="123456")
# parser.add_argument('age',type=int,help='年龄验证错误!')
# parser.add_argument('gender',type=str,choices=['男','女','双性'],help="性别只能是男 或者女 。。。")
# parser.add_argument('birthday',type=inputs.date,help='生日字段验证错误!')
# parser.add_argument('phone',type=inputs.regex(r'1[3578]\d{9}'))
# parser.add_argument('phomepage',type=inputs.url,help='个人中心链接验证错误!')
# #3.利用解析器对象进行验证,若正确,直接返回验证后合格的参数值,若错误,抛异常信息给客户端
# args = parser.parse_args()
# print(args)
# return {"tips":"注册成功"}
#
# api.add_resource(RegisterView,'/register/')
#flask_restful返回标准化参数
# class News(object):
# def __init__(self,title,content):
# self.title =title
# self.content =content
#
# class NewsView(Resource):
# # restful规范中,要求,定义好了返回的参数个数 和 内容
# resource_fields = {
# 'title': fields.String,
# 'content': fields.String
# }
# @marshal_with(resource_fields)
# def get(self):
# # return {'title':"世界太大",'content':"可钱包太小"}
# # 好处1:体现规范化,即使content这个参数没有值,也应该返回,返回一个null回去
# # return {'title':"世界太大"}
# # 好处2:体现规范化,还可以返回一个对象模型回去
# news = News('能力强的体现', '能屈能伸')
# return news
#
# api.add_resource(NewsView,'/news/')
# flask_restful返回标准化参数强化 1.重命名属性和默认值:
# class User():
# def __init__(self,username,age):
# self.username=username
# self.age=age
# # self.signature=None
# self.signature='天道酬勤!!'
#
# class UserView(Resource):
# resource_fields={
# #1.重命名属性
# 'uname':fields.String(attribute='username'),
# 'age':fields.Integer,
# #2.默认值
# 'signature':fields.String(default='此人很懒,什么也没写')
# }
#
# @marshal_with(resource_fields)
# def get(self):
# user = User('莫莫',18)
# return user
#
# api.add_resource(UserView,'/user/')
# flask_restful返回标准化参数强化 2.复杂的参数结构
# 复杂的参数结构
# 实体间关系有 1:1 1:n n:n(转为2个1:n)
# 新闻系统后台 用户 新闻 新闻标签
# class User():
# def __init__(self,id,uname,age):
# self.id = id
# self.uname = uname
# self.age = age
# # __str__ 和 __repr__
# def __repr__(self):
# return "".format(id=self.id, uname=self.uname,age=self.age)
#
# class News():
# def __init__(self,id,title,content):
# self.id=id
# self.title=title
# self.content=content
# #关系映射
# self.author=None
# self.tags=[]
# def __repr__(self):
# return ""\
# .format(id=self.id, title=self.title,content=self.content,author=self.author,tags=self.tags)
#
# class NewsTag():
# def __init__(self,id,name):
# self.id=id
# self.name=name
# def __repr__(self):
# return ''.format(id =self.id , name=self.name)
#
# def createData():
# user = User(110,'莫莫',30)
# tag1 = NewsTag(200,"要闻")
# tag2 = NewsTag(210,"娱乐")
# news =News(300,'吴京征服了世界上海拔最高的派出所','4月23日中午11点,吴京发了一条微博,配文“世界上海拔最高的派出所”,并@了另外一名演员张译。微博中有两张图片,第一张是吴京和张译两人坐在地上的合照,背后几个大字“中国边防”。第二张则是两人与派出所民警们的合照。 ')
# news.author = user #绑定新闻作者
# news.tags.append(tag1) #绑定新闻标签1
# news.tags.append(tag2) #绑定新闻标签2
# print(news)
# return news
#
# class NewsView2(Resource):
# resource_fields={
# 'id':fields.Integer,
# 'title': fields.String,
# 'content': fields.String,
# #如在一个字段下面又是一个字典,那么可以使用fields.Nested({...})
# 'author': fields.Nested({
# 'id': fields.Integer,
# 'uname': fields.String,
# 'age':fields.Integer
# }),
# #如要在一个字段中放置一个列表,那么可以使用fields.List(fields.Nested({...}))
# 'tags': fields.List(fields.Nested({
# 'id': fields.Integer,
# 'name': fields.String
# }))
# }
#
# @marshal_with(resource_fields)
# def get(self):
# news = createData()
# return news
#
# api.add_resource(NewsView2,'/news2/')
# 1.Flask_RESTful结合蓝图使用
# 2.Flask_RESTful渲染模版
if __name__ == '__main__':
app.run(debug=True)
【news.py】
from flask import Blueprint,render_template,make_response,Response
from flask_restful import Api,Resource,reqparse,inputs,fields,marshal_with
news_bp = Blueprint('news',__name__,url_prefix='/news')
api = Api(news_bp) # 此写法适用于 在蓝图文件中使用flask_restful写接口
import json
class User():
def __init__(self,id,uname,age):
self.id = id
self.uname = uname
self.age = age
# __str__ 和 __repr__
def __repr__(self):
return "" .format(id=self.id, uname=self.uname,age=self.age)
class News():
def __init__(self,id,title,content):
self.id=id
self.title=title
self.content=content
#关系映射
self.author=None
self.tags=[]
def __repr__(self):
return "" \
.format(id=self.id, title=self.title,content=self.content,author=self.author,tags=self.tags)
class NewsTag():
def __init__(self,id,name):
self.id=id
self.name=name
def __repr__(self):
return '' .format(id =self.id , name=self.name)
def createData():
user = User(110,'莫莫',30)
tag1 = NewsTag(200,"要闻")
tag2 = NewsTag(210,"娱乐")
news =News(300,'吴京征服了世界上海拔最高的派出所','4月23日中午11点,吴京发了一条微博,配文“世界上海拔最高的派出所”,并@了另外一名演员张译。微博中有两张图片,第一张是吴京和张译两人坐在地上的合照,背后几个大字“中国边防”。第二张则是两人与派出所民警们的合照。 ')
news.author = user #绑定新闻作者
news.tags.append(tag1) #绑定新闻标签1
news.tags.append(tag2) #绑定新闻标签2
print(news)
return news
class NewsView2(Resource):
resource_fields={
'id':fields.Integer,
'title': fields.String,
'content': fields.String,
# 如在一个字段下面又是一个字典,那么可以使用fields.Nested({...})
'author': fields.Nested({
'id': fields.Integer,
'uname': fields.String,
'age':fields.Integer
}),
# 如要在一个字段中放置一个列表,那么可以使用fields.List(fields.Nested({...}))
'tags': fields.List(fields.Nested({
'id': fields.Integer,
'name': fields.String
}))
}
@marshal_with(resource_fields)
def get(self):
news = createData()
return news
api.add_resource(NewsView2,'/news2/')
# 02. 使用flask-restful渲染模版
class ListView(Resource):
def get(self):
return render_template('index.html')
api.add_resource(ListView,'/list/')
# 渲染模版经过修改后,能支持html和json
@api.representation('text/html')
def out_html(data,code,headers):
if isinstance(data, str):
# 在representation装饰的函数中,必须返回一个Response对象
# resp = make_response(data)
resp = Response(data)
return resp
else:
return Response(json.dumps(data), mimetype='application/json')
【index.html】
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h2>flask_restful渲染模版的注意事项h2>
body>
html>