接口概念

  IOP:面向接口编程,不再关注具体的实现;只关注输入、输出。

  http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html

服务器返回数据类型:

  网页数据html,为浏览器使用

  Json数据,ajax javascript发请求的一种方式;也可以使用request的python请求方式

为移动端编写接口关注:

  接口地址是什么:/xxx/yyy/zzz

  接口需要什么参数:参数根据业务场景

  返回什么格式的数据:大多数是json数据

RestfulAPI:

   一种软件架构风格、设计风格、而不是标准,只是提供了一组设计原则和约束条件。它主要用户客户端和服务器交互类的软件。

  基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。REST全程是Representational State Transfer,表征性状态转移。

  首次在2000年Roy Thomas Fielding的博士论文中出现,Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者,

  Apache服务器软件的作者之一,Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了广泛的关注。

理解RESTful

介绍:https://github.com/RockTeach/PythonCourse/blob/master/web/flask/restful.md

  要理解RESTful架构,最好的就是去理解它的单词 Representational State Transfer 到底是什么意思,它的每一个词到底要表达什么。

  REST的释义,"(资源的)表现层状态转化",其实这省略了主语。“表现层”其实指的是“资源(Resource)”的“表现层”。

状态码

  服务器向用户返回的状态码和提示信息,常见的有以下一些地方

  • 200:OK - [GET]:服务器成功返回用户请求的数据
  • 201:CREATED -[POST/PUT/PATCH]:用户新建或修改数据成功
  • 202:Accepted - [*] :表示一个请求已经进入后台排队(异步任务)
  • 204:NO CONTENT - [DELETE]:表示数据删除成功
  • 400:INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误
  • 401:Unauthorized - [*] :表示用户没有权限(令牌,用户名,密码错误)
  • 403:Forbidden - [*]:表示用户得到授权,但是访问是被禁止的
  • 404:NOT FOUND - [*]:用户发出的请求针对的是不存在的记录
  • 406:Not Acceptable - [*]:用户请求格式不可得
  • 410:Gone - [GET] :用户请求的资源被永久移除,且不会再得到的
  • 422:Unprocesable entity -[POST/PUT/PATCH]:当创建一个对象时,发生一个验证错误
  • 500:INTERNAL SERVER EROR - [*] :服务器内部发生错误

资源(Resource)

  所谓“资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。

  它可以是一段文本,一张图片,一首歌曲,一种服务,总之就是一个具体的实例。

  你可以使用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。

  要获取这个资源,访问它的URI就可以了,因此URI就成了每一个资源的地址或独一无二的识别符。所谓“上网”就是与互联网上一系列的“资源”互动,调用它们的URI。

表现层(Representation)

  “资源”是一种信息实体,它可以有多种外在表现形式。我们把“资源”具体呈现出来的形式,叫做它的”表现层“(Representation)。

  URI只代表资源的实体,不代表它的形式。严格地说,有些网站最后的”.html“后缀名是不必要的,因为这个后缀表示格式,属于”表现层“范畴,而URI应该只代表”资源“的位置。

  它的具体表现形式,应该在HTTP请求头的信息中使用Accept和Content-Type字段指定。

状态转换(State Transfer)

  访问一个网站,就代表客户端和服务端的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

  互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务端。

  因此,如果客户端想要操作服务器,就必须通过某种手段,让服务器端发生”状态转换(State Transfer)“。

  而这种转换是建立在表现层之上的,所以就是”表现层状态转化“。

  客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议中,四个表示操作方式的动词:GET,POST,PUT,DELETE。

  它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可用于更新资源),PUT用来更新资源,DELETE用来删除资源

总结 :

  1. 每一个URI代表一种资源
  2. 客户端和服务器之间,传递这种资源的某种表现层
  3. 客户端通过四个HTTP动词,对服务端资源进行操作,实现”表现层状态转换“
  4. 同一个url针对用户的不同的请求操作,表现出来的状态是不同的。表现出来的多种形式,就是表现层状态转换。
  • RESTful是软件架构设计思想。使用在CS,客户端和服务端这种架构模型中。

  • 表现层状态转换

    • 主语 (资源)

    • URI 每个URI代表一种资源

    • 资源展现给我们的形式就叫做表现层

    • 通过HTTP的请求谓词来实现表现层转换

  • 重要概念

    • URI、HTTP请求谓词、JSON

注意:

  postman/前端 在向服务器提交json数据时,需要声明提交的类型。在postman的请求的headers增加content-type:application/json。

  flask 在确认请求数据是通过json提交后,会将json字符产转换成 字典。保存在request.json中

FBV简单体验:

  • views.py
 from flask import Blueprint, request

 restful_bp = Blueprint("restful_bp",__name__)
"""
动作 URL 状态码 数据库操作 含义
GET /posts 200 SELECT 从 blog_posts 表中查询一组数据
POST /posts 201 INSERT 向 blog_posts 表中插入一条数据 GET /posts/123 200 SELECT 从 blog_posts 表中查询 id 为123 的记录
PUT /posts/123 200 UPDATE 更新 blog_posts 表中 id 为123 的记录(请求时提供全部字段的更新)
PATCH /posts/123 200 UPDATE 更新 blog_posts 表中 id 为123 的记录(请求时提供部分字段的更新)
DELETE /posts/123 204 DELETE 删除 blog_posts 表中 id 为123 的记录
""" @restful_bp.route("/posts",methods = ["POST","GET"])
def post_list():
if request.method == "POST":
return "向 blog_posts 表中插入一条数据",201 # 201 表示创建成功
elif request.method == "GET":
return "从 blog_posts 表中查询一组数据",200 @restful_bp.route("/posts/<post_id>",methods=["GET","POST","PUT","PATCH","DELETE"])
def post_detail(post_id):
if request.method == "GET":
return "从 blog_posts 表中查询 id 为{} 的记录".format(post_id),200
elif request.method == "PUT":
return "更新 blog_posts 表中 id 为{} 的记录(请求时提供全部字段的更新)".format(post_id),200
elif request.method == "PATCH":
return "更新 blog_posts 表中 id 为{} 的记录(请求时提供部分字段的更新)".format(post_id),200
elif request.method == "DELETE":
return "删除 blog_posts 表中 id 为{} 的记录".format(post_id),204 # 204 表示删除成功
  •  models.py
 from flask_sqlalchemy import SQLAlchemy

 db = SQLAlchemy()

 class Channel(db.Model):
__tablename__ = "channels" id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(16),unique=True,nullable=False)
sort = db.Column(db.Integer,nullable=False)
# 对象方法。将类的对象形式转化成字典形式
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'sort': self.sort,
}

FBV实现:创建POST | 查询GET

  • views.py

    • POST:http://127.0.0.1:5000/channel_dict
    • GET:http://127.0.0.1:5000/channel_dict
 @restful_bp.route('/channel_dict/',methods=["GET","POST"])
def channel_list():
if request.method == 'POST':
# # 结果:b'{\n\t"\xe5\x90\x8d\xe5\xad\x97":"\xe7\xa7\x91\xe6\x8a\x80",\n\t"sort":1\n}'
# # 需在postman中设置一下请求头headers。Content-Type:application/json
# print(request.data)
# # 结果:None
# print(request.json)
if 'name' not in request.json or 'sort' not in request.json:
return abort(400) channel = Channel()
channel.name = request.json['name']
channel.sort = request.json['sort'] db.session.add(channel)
db.session.commit() return jsonify({'channel':channel.to_dict()}),201 elif request.method == "GET":
# 数据库查询的返回的是list类型的数据
_channels = Channel.query.all()
# 将数据库中查询出的对象 转化成 字典形式
channels = [channel.to_dict() for channel in _channels]
# flask视图函数只能返回 str 或 response 对象。可以将数据库查询出来的转化成json,以满足flask视图函数的返回要求
ret = {
'channels':channels
}
# import json
# json_str = json.dumps(ret)
# return json_str
return jsonify(ret)

FBV实现:GET | PUT | PATCH | DELETE

  • views.py:http://127.0.0.1:5000/channels/2
 @restful_bp.route("/channels/<channel_id>",methods=["GET","POST","PUT","PATCH","DELETE"])
def channel_detail(channel_id):
    # 根据条件查询对象
channel = Channel.query.get(channel_id) # 获取信息:http://127.0.0.1:5000/channel
if request.method == "GET":
return jsonify({'channel':channel.to_dict()}),200 # 更新数据:全量更新
elif request.method == "PUT":
if 'name' not in request.json or 'sort' not in request.json:
return abort(400)
channel.name = request.json['name']
channel.sort = request.json['sort']
db.session.add(channel)
db.session.commit()
return jsonify({'channel':channel.to_dict()}),200 # 更新数据:差量更新
elif request.method == 'PATCH':
# name = channel.name
# if 'name' in request.json:
# name = request.json['name']
# channel.name = name
# 等价于 上四行代码。如果有数据更新就更新{先从json中获取数据,如果有就赋值给channel.name},没有数据更新就用原来的当做默认值
channel.name = request.json.get('name',channel.name)
channel.sort = request.json.get('sort',channel.sort)
db.session.commit()
return jsonify({'channel':channel.to_dict()}),200 # 删除数据。删除成功后返回的是空数据。
elif request.method == "DELETE":
db.session.delete(channel)
db.session.commit()
return "",204 

Flask-RestfulApi

框架优点:

  • 会让代码逻辑更加清晰,不会再有过多的if-else语句
  • 框架会提供参数的验证。像form一样提供验证数据的功能
  • 框架会提供丰富的输出格式,自定义输出的结构

框架注意:⚠️

  1. flask-restful 返回字典。框架内部自动转换为json。return {'channels':channels},200
  2. 如果在扩展文件ext.py实例化和注册路由资源,必须在加载时就注册好,不可以在调用函数懒加载时注册
  3. 根据请求的同名方法执行同名的视图函数,来完成不同的请求。request.method.lower() 获取请求方式然后将其变成小写

CBV简单体验:pip install Flask-RESTful  

    # method = request.method
# method = lower(method)
# 获取请求方式后将其转化为小写,然后去类中匹配,如果有同名的函数,就执行相应的请求方法函数 # Resource 是一个资源类,其实就是一个url
# Resource 的父类MethodView是flask自己的views中的一个类,不同Resource我们自己也可以完成各种请求。
# Resource 的父类MethodView也是根据不同的请求方法执行不同的请求函数,来完成各种请求操作
# 源码变小写 meth = getattr(self, request.method.lower(), None)。getattr是从一个实例中将类中的一个方法取出来赋值给一个变量,执行这个变量就是执行此函数方法

CBV类视图

 from flask import Flask
from flask_restful import Api, Resource app = Flask(__name__)
api = Api(app)
"""
动作 URL 状态码 数据库操作 含义
GET /posts 200 SELECT 从 blog_posts 表中查询一组数据
POST /posts 201 INSERT 向 blog_posts 表中插入一条数据
"""
class PostList(Resource):
"""
flask-restful 的所有请求是通过 类 来处理的。继承自Resource类。
flask-restful 框架内部会自动根据请求的HTTP METHOD调用同名的实例方法
GET: /posts -> def get(self): pass
POST:/posts -> def post(self): pass
"""
def get(self):
return "从 blog_posts 表中查询一组数据",200 def post(self):
return "向 blog_posts 表中插入一条数据",201 """
动作 URL 状态码 数据库操作 含义
GET /posts/123 200 SELECT 从 blog_posts 表中查询 id 为123 的记录
PUT /posts/123 200 UPDATE 更新 blog_posts 表中 id 为123 的记录(请求时提供全部字段的更新)
PATCH /posts/123 200 UPDATE 更新 blog_posts 表中 id 为123 的记录(请求时提供部分字段的更新)
DELETE /posts/123 204 DELETE 删除 blog_posts 表中 id 为123 的记录
"""
class PostDetail(Resource):
"""
flask-restful 框架内部也支持 URL 上配置的路由参数,路由参数会传递到具体处理请求的实例方法中
"""
def get(self,post_id):
return "从 blog_posts 表中查询 id 为{} 的记录".format(post_id),200 def put(self,post_id):
return "更新 blog_posts 表中 id 为{} 的记录(请求时提供全部字段的更新)".format(post_id),200 def patch(self,post_id):
return "更新 blog_posts 表中 id 为{} 的记录(请求时提供部分字段的更新)".format(post_id),200 def delete(self,post_id):
return "删除 blog_posts 表中 id 为{} 的记录".format(post_id),204 # 路由配置。参数[前两个参数必填]:(resource类(资源类)、访问的url地址、endpoint="相当于一个路由名称 如:blue.login。可以在url_for中使用")
api.add_resource(PostList,'/posts',endpoint='post_list') # 如果不定义endpoint参数,默认endpoint的值是 类名
api.add_resource(PostDetail,'/posts/<int:post_id>',endpoint='post_detail') if __name__ == '__main__':
app.run(debug=True)
 # 非restfulAIPI中不用装饰器的写法
# @app.route("/")
def index():
return "Index" # 参数:路由、描述、资源
app.add_url_rule("/index/","index",index) if __name__ == '__main__':
app.run(debug=True)

非API非装饰器写法

简单拆分格式:

  • manage.py、ext.py、models.py
from flask_script import Manager
from flask_migrate import MigrateCommand
from app import create_app app = create_app()
manager = Manager(app)
manager.add_command("db",MigrateCommand) if __name__ == '__main__':
manager.run()

manage.py

import os
from flask_migrate import Migrate
from app.models import db migrate = Migrate() def init_db(app):
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(app.root_path, 'sqlite3.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app=app) def init_migrate(app):
migrate.init_app(app=app,db=db)

ext.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Channel(db.Model):
__tablename__ = "channels" id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(16),unique=True,nullable=False)
sort = db.Column(db.Integer,nullable=False)
# 对象方法。将类的对象形式转化成字典形式
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'sort': self.sort,
}

models.py

  • __innit__.py
 from flask import Flask
from flask_restful import Api
from app import ext
from app.apis import ChannelList, ChannelDetail
from app.views import restful_bp def create_app():
app = Flask(__name__) ext.init_db(app)
ext.init_migrate(app) # 注册实例化api扩展
api = Api(app)
# 路由注册
api.add_resource(ChannelList, '/api/ChannelList', endpoint='ChannelList')
api.add_resource(ChannelDetail, '/api/ChannelDetail/<int:id>',endpoint='ChannelDetail')
# 蓝图注册
app.register_blueprint(blueprint=restful_bp)
return app
  • api.py 初级[在models.py中定义函数用来字段转字典格式]
 from flask_restful import Resource,reqparse
from app.models import Channel, db # 输出格式化。字段自定义验证函数。自定义验证完成后,必须把验证通过后的数值返回出去以方便后续保存操作
def validate_channel_name(value):
if Channel.query.filter_by(name=value).count() > 0:
raise ValueError("频道名重复")
return value # 输入的验证。flask-restful通过reqparse包中的RequestParser类提供客户端请求的数据参数(通常是json)验证校验功能
# 验证需要的参数(客户端提交的需要验证的字段名称,required=True表示必填项,类型,help="错误提示信息")
channel_parser = reqparse.RequestParser()
channel_parser.add_argument('name',required=True,type=validate_channel_name) # type='自定义验证函数名'
channel_parser.add_argument('sort',required=True,type=int,help='sort字段为为必填项,int类型') # http://127.0.0.1:5000/api/ChannelList [get请求、post请求]
class ChannelList(Resource):
"""
GET /channels
POST /channels
"""
def get(self):
# 数据库查询返回的是list类型的数据。需要将从数据库查询到的数据转为字典形式
_channels = Channel.query.all()
channels = [channel.to_dict() for channel in _channels]
# flask中视图函数只能返回str或者response对象。
# flask-restful可以将数据库中查询出来的数据转换成json;以满足flask视图函数的返回要求
# flask-restful返回字典,框架内部自动转换为json。return {'channels':channels},200
res = {
'channels':channels
}
return res,200 def post(self):
# 通过RequestParser的实例对象 验证前端页面传递来的数据。如果验证不通过返回400错误
args = channel_parser.parse_args() channel = Channel()
channel.name = args['name']
channel.sort = args['sort']
db.session.add(channel)
db.session.commit()
     # flask-restful 的类视图方法只能返回字典格式
return {'channel':channel.to_dict()},201
  • api.py 高级[使用装饰器转字典]
 from flask_restful import Resource, reqparse, fields, marshal_with, abort
from app.models import Channel, db def validate_channel_name(value):
if Channel.query.filter_by(name=value).count() > 0:
raise ValueError("频道名重复")
return value
channel_parser = reqparse.RequestParser()
channel_parser.add_argument('name',required=True,type=validate_channel_name)
channel_parser.add_argument('sort',required=True,type=int,help='sort字段为为必填项,int类型') # 通过marshal_with和fields一起完成自定义输出的功能,让api接口可以返回对象,系统内部将对象根据fields的定义格式转换成字段类型
channel_fields = {
"id":fields.Integer,
# url链接。"url": "http://127.0.0.1:5000/api/ChannelDetail/3",
"url":fields.Url(endpoint="ChannelDetail",absolute=True), # absolute=True 表示加上前缀http://127.0.0.1:5000
"name":fields.String,
"sort":fields.Integer,
}
 # http://127.0.0.1:5000/api/channels  可以get、post请求
class ChannelList(Resource): @marshal_with(fields=channel_fields)
def get(self):
_channels = Channel.query.all()
return _channels, 200
# 原来写法
# channels = [channel.to_dict() for channel in _channels]
# res = {
# 'channels':channels
# }
# return res,200 # 此装饰器接收一个参数(以什么格式)。有了这个装饰器,在返回的时候对象会按照参数同名所设置的方式变成一个字典返回
@marshal_with(fields=channel_fields)
def post(self):
# 验证前端页面传递来的数据。如果验证不通过返回400错误
args = channel_parser.parse_args() channel = Channel()
channel.name = args['name']
channel.sort = args['sort']
db.session.add(channel)
db.session.commit()
# 原来返回方式
# return {'channel':channel.to_dict()},201
# flask-restful只能返回字典格式类型。添加装饰器marshal_with可以定制输出格式。
return channel,201
 # http://127.0.0.1:5000/api/ChannelDetail/3
class ChannelDetail(Resource):
"""
GET /channels/123
PUT /channels/234
PATCH /channels/123
DELETE /channels/123
"""
def get_object(self,id):
channel = Channel.query.get(id)
if channel is None:
return abort(404,message="找不到对象")
return channel @marshal_with(fields=channel_fields)
def get(self,id):
channel = self.get_object(id)
return channel,200 @marshal_with(fields=channel_fields)
def put(self,id):
channel = self.get_object(id)
args = channel_parser.parse_args() # 字段验证 channel.name = args.get("name",channel.name)
channel.sort = args.get("sort",channel.sort)
db.session.commit()
return channel,200 def patch(self,id):
self.put(id) def delete(self,id):
channel = self.get_object(id)
db.session.delete(channel)
db.session.commit()
return "",204


API 1:N 模型

  坑:'/api/ArticleDetails/<int:id>' 此id必须和数据库中的相应字段同名,否则匹配不上;.Nested:表示将一个比较复杂的数据对象拆分开,方便转为字典格式

 from flask import Flask
from flask_restful import Api
from app import ext
from app.apis import ChannelList, ChannelDetail, ArticleList, ArticleDetail
from app.views import restful_bp def create_app():
app = Flask(__name__) ext.init_db(app)
ext.init_migrate(app) # 注册实例化api扩展
api = Api(app)
# 注册频道路由
api.add_resource(ChannelList, '/api/ChannelLists', endpoint='ChannelLists')
api.add_resource(ChannelDetail, '/api/ChannelDetails/<int:id>',endpoint='ChannelDetails')
# 注册文章路由
api.add_resource(ArticleList, '/api/Articles', endpoint='Articles')
api.add_resource(ArticleDetail, '/api/ArticleDetails/<int:id>',endpoint='ArticleDetails') # 蓝图
app.register_blueprint(blueprint=restful_bp)
return app

__init__.py

 import datetime
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() # 频道 1
class Channel(db.Model):
__tablename__ = "channels" id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(16),unique=True,nullable=False)
sort = db.Column(db.Integer,nullable=False) articles = db.relationship('Article',backref='channel',lazy='dynamic') # 文章 N
class Article(db.Model):
__tablename__ = "articles" id = db.Column(db.Integer,primary_key=True)
created_at = db.Column(db.DateTime,default=datetime.datetime.now())
updated_at = db.Column(db.DateTime,default=datetime.datetime.now(),onupdate=datetime.datetime.now())
title = db.Column(db.String(256),nullable=False)
content = db.Column(db.String(5000),nullable=False) channel_id = db.Column(db.Integer,db.ForeignKey("channels.id"))

models.py

 import datetime
from flask_restful import Resource, reqparse, fields, marshal_with, abort
from app.models import Channel, db, Article # ============================ N ===================================
# 自定义一个类,用于时间格式化
class MyDTFmt(fields.Raw):
def format(self, value):
return datetime.datetime.strftime(value,'%Y-%m-%d %H:%M:%S') # 定义参数验证格式
article_parser = reqparse.RequestParser()
article_parser.add_argument('title',required=True,type=str,help="标题必填")
article_parser.add_argument('content',required=True,type=str,help="正文必填")
article_parser.add_argument('channel_id',required=True,type=int,help="频道必填") # 定义返回输出格式
article_fields = {
'id':fields.Integer,
'url':fields.Url(endpoint='ArticleDetails',absolute=True),
'title':fields.String,
'content':fields.String,
# 等同于:'channel':fields.Nested(channel_fields),
'channel':fields.Nested({ # 通过Nested将对象解开
'name':fields.String,
'url':fields.Url(endpoint="ChannelDetails",absolute=True),
"sort": fields.Integer,
}),
'created_at':MyDTFmt, # 进行自定义时间格式化
'updated_at':fields.DateTime(dt_format="iso8601") } # 文章模块。get、post
class ArticleList(Resource): @marshal_with(fields=article_fields)
def get(self):
articles = Article.query.all()
return articles,200 @marshal_with(fields=article_fields)
def post(self):
args = article_parser.parse_args() article = Article()
article.title = args.get('title')
article.content = args.get('content')
article.channel_id = args.get('channel_id') db.session.add(article)
db.session.commit()
return article,201 # 文章模块。get、put、patch、delete
class ArticleDetail(Resource):
def get_object(self,id):
article = Article.query.get(id)
if article is None:
return abort(404,message="找不到对象")
return article @marshal_with(fields=article_fields)
def get(self,id):
article = self.get_object(id)
return article,200 def put(self,id):
pass
def patch(self,id):
pass
def delete(self,id):
pass # ================================== 1 =========================================
# 自定义字段验证函数。 自定义验证后,必须把验证通过后的数值返回出去
def validate_channel_name(value):
if Channel.query.filter_by(name=value).count() > 0:
raise ValueError("频道名重复")
return value channel_parser = reqparse.RequestParser()
channel_parser.add_argument('name',required=True,type=validate_channel_name) # type=自定义验证函数名
channel_parser.add_argument('sort',required=True,type=int,help='sort字段为为必填项,int类型') channel_fields = {
"id":fields.Integer,
"url":fields.Url(endpoint="ChannelDetails",absolute=True),
"name":fields.String,
"sort":fields.Integer,
} channel_article_fields = {
"id": fields.Integer,
"url": fields.Url(endpoint="ChannelDetails",absolute=True),
"name": fields.String,
"articles": fields.List(fields.Nested(article_fields)) # 列表是一个articles对象,通过Nested将其解开,输出出去。
} # 频道模块。get、post
class ChannelList(Resource): @marshal_with(fields=channel_fields)
def get(self):
_channels = Channel.query.all()
return _channels, 200 # 此装饰器接收一个参数(以什么格式)。有了这个装饰器,在返回的时候对象会按照同名参数设置的方式变成一个字典返回
@marshal_with(fields=channel_fields)
def post(self):
# 验证前端页面传递来的数据。如果验证不通过返回400错误
args = channel_parser.parse_args() channel = Channel()
channel.name = args['name']
channel.sort = args['sort']
db.session.add(channel)
db.session.commit()
return channel,201 # 频道模块。get、put、patch、delete
class ChannelDetail(Resource):
"""
GET /channels/123
PUT /channels/234
PATCH /channels/123
DELETE /channels/123
"""
def get_object(self,id):
channel = Channel.query.get(id)
if channel is None:
return abort(404,message="找不到对象")
return channel @marshal_with(fields=channel_article_fields)
def get(self,id):
channel = self.get_object(id) # channel.articles 代表了当前频道下文章列表
return channel,200 @marshal_with(fields=channel_fields)
def put(self,id):
channel = self.get_object(id)
args = channel_parser.parse_args() # 字段验证 channel.name = args.get("name",channel.name)
channel.sort = args.get("sort",channel.sort)
db.session.commit()
return channel,200 def patch(self,id):
self.put(id) def delete(self,id):
channel = self.get_object(id)
db.session.delete(channel)
db.session.commit()
return "",204

高级拆分格式:

    

  • manage.py
 """ manage.py """

 import os
from flask_migrate import MigrateCommand
from flask_script import Manager
from day05_chaiAdvanced import create_app # 从系统环境中获取参数FLASK_ENV的值给env,判断是什么环境下的服务器
# 避免外人修改代码,方便代码放在什么环境服务器下,就在什么环境下运行
# 在系统终端 vim .bashrc 编写系统环境变量:#FLASK_ENV。export FLASK_ENV = "develop" 保存退出
env = os.environ.get("FLASK_ENV") or 'default' # 首先创建一个flask对象、加载配置、加载扩展库、初始化路由
app = create_app(env) # flask-scripy扩展
manager = Manager(app)
manager.add_command("db",MigrateCommand) if __name__ == '__main__':
manager.run()
  • __init__.py
 ''' 启动项目的__init__.py '''
from flask import Flask from day05_chaiAdvanced.settings import Config, envs
from day05_chaiAdvanced.extension import init_ext
from day05_chaiAdvanced.views import init_api def create_app(env): # 创建Flask对象
app = Flask(__name__,template_folder="../templates") # 加载初始化配置。 从类对象中加载。env参数确定在什么环境下的
app.config.from_object(envs.get(env)) # 加载初始化扩展库。通过懒加载的方式加载(调用函数时参数的传递)
init_ext(app) # 加载初始化api路由器。通过懒加载的方式加载(调用函数时参数的传递)
init_api(app) return app
  • views.py
 from Book.route import books_api

 def init_api(app):
books_api.init_app(app)
  • books/route.py
 from flask_restful import Api

 from Book.views import BooksResource

 books_api = Api()

 books_api.add_resource(BooksResource, "/books/")
  • books/views.py
 from flask_restful import Resource

 class BooksResource(Resource):

     def get(self):
return {"msg": "book ok"}


 

最新文章

  1. C# 使用AForge调用笔记本摄像头拍照
  2. [2014.01.27]wfPng 水印贴图组件 2.1
  3. 56相册视频(土豆相册视频 激动相册视频 QQ动感影集等)——下载教程
  4. CentOS 安装
  5. Make Rules
  6. nginx的基本配置和虚拟主机的配置
  7. python--列表生成式--8
  8. Comparator与Comparable的异同
  9. 2729:[HNOI2012]排队 - BZOJ
  10. C# 自定义光标 WaitCursor
  11. jquery-制作选项卡
  12. Angular 4 学习笔记 从入门到实战 打造在线竞拍网站 基础知识 快速入门 个人感悟
  13. Ubantu 16.4 samba安装配置
  14. 【转载】FPGA算法设计随笔
  15. 如何使用JavaScript实现纯前端读取和导出excel文件
  16. springboot 格式化返回日期
  17. iis7.0 发生未知 FastCGI错误,错误代码 0x8007010b 的解决办法
  18. 深入浅出 JVM GC(3)
  19. 在ls命令中使用通配符
  20. Our Journey of Xian Ends

热门文章

  1. TXNLP 09-17
  2. Python之文字转图片
  3. Practical, Dynamic Visibility for Games(可实现动态显示技术)
  4. 题解 [SHOI2010]最小生成树
  5. 解决微信小程序textarea 里输入的文字或者是placeholder里的值,飘到弹出view上
  6. attr(name|properties|key,value|fn)
  7. Linux Shell脚本,删除旧文件,保留最新的几个文件
  8. JavaWeb-SpringBoot(抖音)_二、服务器间通讯
  9. HDU 5795 A Simple Nim ——(Nim博弈 + 打表)
  10. [JZOJ5400]:Repulsed(贪心+树形DP)