赞
踩
Django 和 Flask 一直都是 Python 开发 Web 的首选,而 Flask 的微内核更适用于现在的云原生微服务框架。但是 Flask 只是一个微型的 Web 引擎,所以我们需要扩展 Flask 使其发挥出更强悍的功能。
python flask框架详解:https://blog.csdn.net/shifengboy/article/details/114274271
Flask-RESTful
Flask-RESTful 就是 Flask 扩展中的佼佼者,它增加了对快速构建 RESTful API 的支持,将 Flask 封装了一层,使其更容易、更快速、更便捷的开发 RESTful API。
GitHub:https://github.com/flask-restful/flask-restful
英文文档:https://flask-restful.readthedocs.io/en/latest/
中文文档:http://www.pythondoc.com/Flask-RESTful/
Flask-RESTPlus
我们知道 Flask-RESTful 是 Flask 的扩展,而 Flask-RESTPlus 则是 Flask-RESTful 的扩展,对 Flask-RESTful 完全兼容且对其进行增强了接口文档的支持。
Flask-RESTPlus 提供了一个连贯的装饰器和工具集合来描述文档 API 所需要的参数和对象,并使用 Swagger 将其解析成正确的接口文档。
GitHub:https://github.com/noirbizarre/flask-restplus
Docs:https://flask-restplus.readthedocs.io/en/latest/
Flask-RESTX
既然已经有了很完美的 Flask-RESTPlus,那为什么还需要 Flask-RESTX 呢?
其实在很长时间中我都一直都在使用 Flask-RESTPlus,但是难受的是作者丢了!没错,就是物理意义上的丢了,Flask-RESTPlus 这个项目团队的成员都找不动他了,团队为了持续维护这个项目只能另开一个分支,将 Flask-RESTPlus 继续延续下去,继续延续后的项目就是 Flask-RESTX。Flask-RESTX
完全兼容Flask-RESTPlus
,Flask-RESTPlus
项目里积攒的问题、BUG
都由Flask-RESTX
完全继承并且社区团队在积极维护汇总,GitHub:https://github.com/python-restx/flask-restx
Docs:https://flask-restx.readthedocs.io/en/latest/
FastAPI
FastAPI 是独立于 Flask 的新式 Web 框架,虽然能看到很多 Flask 和相关扩展的影子,但是它也成为不可忽视的 Web 框架之一,而且 FastAPI 还号称是最快的Python框架之一。
GitHub:https://github.com/tiangolo/fastapi
Docs:https://fastapi.tiangolo.com
安装:pip install flask-restful
一个最小的 Flask-RESTful API 像这样:
- from flask import Flask
- from flask_restful import Resource, Api
-
- app = Flask(__name__)
- api = Api(app)
-
-
- class HelloWorld(Resource):
- def get(self):
- return {'hello': 'world'}
-
-
- api.add_resource(HelloWorld, '/')
-
- if __name__ == '__main__':
- app.run(debug=True)
把上述代码保存为 api.py 并且在你的 Python 解释器中运行它。需要注意地是我们已经启用了 Flask 调试 模式,这种模式提供了代码的重载以及更好的错误信息。调试模式绝不能在生产环境下使用。
$ python api.py
* Running on http://127.0.0.1:5000/
现在打开一个新的命令行窗口使用 curl 测试你的 API:
$ curl http://127.0.0.1:5000/
{"hello": "world"}
视图中的类 需要继承 flask_restful 中的 Resource
Flask-RESTful 提供的主要构建块是资源。资源构建在 Flask 可插入视图之上,只需在资源上定义方法,就可以轻松访问多个 HTTP 方法。一个 todo 应用程序的基本 CRUD 资源是这样的:
- from flask import Flask, request
- from flask_restful import Resource, Api
-
- app = Flask(__name__)
- api = Api(app)
-
- todos = {}
-
-
- class TodoSimple(Resource):
- def get(self, todo_id):
- return {todo_id: todos[todo_id]}
-
- def put(self, todo_id):
- todos[todo_id] = request.form['data']
- return {todo_id: todos[todo_id]}
-
-
- api.add_resource(TodoSimple, '/<string:todo_id>')
-
- if __name__ == '__main__':
- app.run(debug=True)
你可以尝试这样:
$ curl http://localhost:5000/todo1 -d "data=Remember the milk" -X PUT
{"todo1": "Remember the milk"}
$ curl http://localhost:5000/todo1
{"todo1": "Remember the milk"}
$ curl http://localhost:5000/todo2 -d "data=Change my brakepads" -X PUT
{"todo2": "Change my brakepads"}
$ curl http://localhost:5000/todo2
{"todo2": "Change my brakepads"}
或者如果你安装了 requests 库的话,可以从 python shell 中运行:
>>> from requests import put, get
>>> put('http://localhost:5000/todo1', data={'data': 'Remember the milk'}).json()
{u'todo1': u'Remember the milk'}
>>> get('http://localhost:5000/todo1').json()
{u'todo1': u'Remember the milk'}
>>> put('http://localhost:5000/todo2', data={'data': 'Change my brakepads'}).json()
{u'todo2': u'Change my brakepads'}
>>> get('http://localhost:5000/todo2').json()
{u'todo2': u'Change my brakepads'}
Flask-RESTful 支持视图方法多种类型的返回值。同 Flask 一样,你可以返回任一迭代器,它将会被转换成一个包含原始 Flask 响应对象的响应。Flask-RESTful 也支持使用多个返回值来设置响应代码和响应头,如下所示:
- from flask import Flask, request
- from flask_restful import Resource, Api
-
- app = Flask(__name__)
- api = Api(app)
-
- todos = {}
-
-
- class TodoSimple(Resource):
- def get(self, todo_id):
- return {todo_id: todos[todo_id]}
-
- def put(self, todo_id):
- todos[todo_id] = request.form['data']
- return {todo_id: todos[todo_id]}
-
-
- class Todo1(Resource):
- def get(self):
- # Default to 200 OK
- return {'task': 'Hello world'}
-
-
- class Todo2(Resource):
- def get(self):
- # Set the response code to 201
- return {'task': 'Hello world'}, 201
-
-
- class Todo3(Resource):
- def get(self):
- # Set the response code to 201 and return custom headers
- return {'task': 'Hello world'}, 201, {'Etag': 'some-opaque-string'}
-
-
- api.add_resource(TodoSimple, '/<string:todo_id>')
-
- if __name__ == '__main__':
- app.run(debug=True)
测试
curl -i http://127.0.0.1:5000/todo1
curl -i http://127.0.0.1:5000/todo2
curl -i http://127.0.0.1:5000/todo3
很多时候,在一个 API 中,你的资源会有多个 url。可以将多个 url 传递给 Api 对象上的 add _ resource ()方法。每一个都将被路由到Resource
api.add_resource(HelloWorld,
'/',
'/hello')
你也可以为你的资源方法指定 endpoint 参数。
api.add_resource(Todo,
'/todo/<int:todo_id>', endpoint='todo_ep')
示例
- from flask import Flask
- from flask_restful import Resource, Api
-
- app = Flask(__name__)
- api = Api(app)
-
-
- class HelloWorld(Resource):
- def get(self):
- return {'hello': 'world'}
-
-
- class Todo(Resource):
- def get(self, todo_id):
- # Default to 200 OK
- return {'task': 'Hello world'}
-
-
- api.add_resource(HelloWorld, '/', '/hello')
- api.add_resource(Todo, '/todo/<int:todo_id>', endpoint='todo_ep')
-
- if __name__ == '__main__':
- app.run(debug=True)
测试
curl http://127.0.0.1:5000/
curl http://127.0.0.1:5000/hello
curl http://127.0.0.1:5000/todo/1
curl http://127.0.0.1:5000/todo/2
尽管 Flask 能够简单地访问请求数据(比如查询字符串或者 POST 表单编码的数据),验证表单数据仍然很痛苦。Flask-RESTful 内置了支持验证请求数据,它使用了一个类似 argparse 的库。
示例
- from flask import Flask
- from flask_restful import reqparse, Api, Resource
-
- app = Flask(__name__)
- api = Api(app)
-
- parser = reqparse.RequestParser()
- parser.add_argument('rate', type=int, help='Rate to charge for this resource')
-
-
- class Todo(Resource):
- def post(self):
- args = parser.parse_args()
- print(args)
- # Default to 200 OK
- return {'task': 'Hello world'}
-
-
- api.add_resource(Todo, '/todos')
-
- if __name__ == '__main__':
- app.run(debug=True)
测试
curl -d 'rate=100' http://127.0.0.1:5000/todos
curl -d 'rate=foo' http://127.0.0.1:5000/todos
与 argparse 模块不同,reqparse. RequestParser.parse _ args ()返回 Python 字典,而不是自定义数据结构。
输入模块提供了许多常用的转换函数,例如 inputs.date ()和 inputs.url ()。
使用 strict = True 调用 parse _ args 可以确保在请求包含您的解析器没有定义的参数时抛出错误。
args = parser.parse_args(strict=True)
curl -d 'rate2=foo' http://127.0.0.1:5000/todos
默认情况下,在你的返回迭代中所有字段将会原样呈现。尽管当你刚刚处理 Python 数据结构的时候,觉得这是一个伟大的工作,但是当实际处理它们的时候,会觉得十分沮丧和枯燥。为了解决这个问题,Flask-RESTful 提供了 fields 模块和 marshal_with() 装饰器。类似 Django ORM 和 WTForm,你可以使用 fields 模块来在你的响应中格式化结构。
- from flask import Flask
- from flask_restful import fields, marshal_with, Resource, Api
-
- app = Flask(__name__)
- api = Api(app)
-
- resource_fields = {
- 'task': fields.String,
- 'uri': fields.Url('todo')
- }
-
-
- class TodoDao(object):
- def __init__(self, todo_id, task):
- self.todo_id = todo_id
- self.task = task
-
- # This field will not be sent in the response
- self.status = 'active'
-
-
- class Todo(Resource):
- @marshal_with(resource_fields)
- def get(self, **kwargs):
- return TodoDao(todo_id='my_todo', task='Remember the milk')
-
-
- api.add_resource(Todo, '/todo')
-
- if __name__ == '__main__':
- app.run(debug=True)
上面的例子接受一个 python 对象并准备将其序列化。marshal_with() 装饰器将会应用到由 resource_fields 描述的转换。从对象中提取的唯一字段是 task。fields.Url 域是一个特殊的域,它接受端点(endpoint)名称作为参数并且在响应中为该端点生成一个 URL。许多你需要的字段类型都已经包含在内。请参阅 fields 指南获取一个完整的列表。
$ curl http://127.0.0.1:5000/todo
{
"task": "Remember the milk",
"uri": "/todo"
}
- from flask import Flask
- from flask_restful import reqparse, abort, Api, Resource
-
- app = Flask(__name__)
- api = Api(app)
-
- TODOS = {
- 'todo1': {'task': 'build an API'},
- 'todo2': {'task': '?????'},
- 'todo3': {'task': 'profit!'},
- }
-
-
- def abort_if_todo_doesnt_exist(todo_id):
- if todo_id not in TODOS:
- abort(404, message="Todo {} doesn't exist".format(todo_id))
-
-
- parser = reqparse.RequestParser()
- parser.add_argument('task')
-
-
- # Todo
- # shows a single todo item and lets you delete a todo item
- class Todo(Resource):
- def get(self, todo_id):
- abort_if_todo_doesnt_exist(todo_id)
- return TODOS[todo_id]
-
- def delete(self, todo_id):
- abort_if_todo_doesnt_exist(todo_id)
- del TODOS[todo_id]
- return '', 204
-
- def put(self, todo_id):
- args = parser.parse_args()
- task = {'task': args['task']}
- TODOS[todo_id] = task
- return task, 201
-
-
- # TodoList
- # shows a list of all todos, and lets you POST to add new tasks
- class TodoList(Resource):
- def get(self):
- return TODOS
-
- def post(self):
- args = parser.parse_args()
- todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1
- todo_id = 'todo%i' % todo_id
- TODOS[todo_id] = {'task': args['task']}
- return TODOS[todo_id], 201
-
-
- ##
- ## Actually setup the Api resource routing here
- ##
- api.add_resource(TodoList, '/todos')
- api.add_resource(Todo, '/todos/<todo_id>')
-
- if __name__ == '__main__':
- app.run(debug=True)
测试
curl http://localhost:5000/todos 获取列表
curl http://localhost:5000/todos/todo3 获取一个单独任务
删除一个任务
$ curl http://localhost:5000/todos/todo2 -X DELETE -v
* Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 5000 failed: Connection refused
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> DELETE /todos/todo2 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 204 NO CONTENT
< Content-Type: application/json
< Server: Werkzeug/1.0.1 Python/3.9.2
< Date: Sat, 06 Mar 2021 03:29:33 GMT
<
* Closing connection 0
增加一个新的任务
$ curl http://localhost:5000/todos -d "task=something new" -X POST -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 5000 failed: Connection refused
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> POST /todos HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 18
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 18 out of 18 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 32
< Server: Werkzeug/1.0.1 Python/3.9.2
< Date: Sat, 06 Mar 2021 03:31:02 GMT
<
{
"task": "something new"
}
* Closing connection 0
更新一个任务
$ curl http://localhost:5000/todos/todo3 -d "task=something different" -X PUT -v
* Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 5000 failed: Connection refused
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> PUT /todos/todo3 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 24
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 24 out of 24 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 38
< Server: Werkzeug/1.0.1 Python/3.9.2
< Date: Sat, 06 Mar 2021 03:32:44 GMT
<
{
"task": "something different"
}
* Closing connection 0
获取最新列表
$ curl http://localhost:5000/todos
{
"todo1": {
"task": "build an API"
},
"todo3": {
"task": "something different"
},
"todo4": {
"task": "something new"
}
}
安装:pip install gunicorn
gunicorn 部署 flask 项目简单示例:https://blog.csdn.net/feng_1_ying/article/details/107469379
- from flask import *
- from flask_restful import Api,Resource,reqparse
- from gevent import monkey
- from gevent.pywsgi import WSGIServer
-
-
- monkey.patch_all()
-
- app=Flask(__name__)
- api=Api(app)
-
- class infoView(Resource):
- def post(self):
- parser = reqparse.RequestParser()
- parser.add_argument('username', type=str)
- args = parser.parse_args()
- return args
- api.add_resource(infoView,'/info/')
- if __name__ == '__main__':
- http_server = WSGIServer(('10.45.7.11', int(5001)), app)
- http_server.serve_forever()
-
- # 部署方案
- # gunicorn -k gevent -b 10.45.7.11:5001 flask_restful_test:app
示例:
- from flask import Flask
- from flask_restful import Api, Resource, fields, marshal
-
- app = Flask(__name__)
- api = Api(app)
-
- # 定义一个示例数据
- data = {
- 'name_1': 'John',
- 'age_1': 30,
- 'email_address': 'john@example.com',
- }
-
- # 定义字段格式和过滤器
- resource_fields = {
- 'name_1': fields.String,
- 'name_2': fields.String,
- 'age_2': fields.Integer,
- # 可以使用 attribute 指定源数据的键
- 'email': fields.String(attribute='email_address')
- }
-
-
- class HelloWorld(Resource):
- def get(self):
- # 序列化数据
- serialized_data = marshal(data, resource_fields)
- return serialized_data
-
-
- api.add_resource(HelloWorld, '/hello', '/', '/world')
-
- if __name__ == '__main__':
- app.run(debug=True)
:https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/
Flask-SQLAlchemy 是一个与 Flask 配合使用的 SQLAlchemy 扩展,它提供了在 Flask 应用程序中使用 SQLAlchemy 进行数据库操作的便利方法和工具。
安装 flask_sqlalchemy 扩展:pip install flask_sqlalchemy
- from flask import Flask
- from flask_sqlalchemy import SQLAlchemy
-
- app = Flask(__name__)
- app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mydatabase.db'
- db = SQLAlchemy(app)
-
-
- class User(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- username = db.Column(db.String(80), unique=True, nullable=False)
- email = db.Column(db.String(120), unique=True, nullable=False)
-
- def __repr__(self):
- return '<User %r>' % self.username
-
-
- # 创建数据表
- db.create_all()
-
- # 插入数据
- user = User(username='john', email='john@example.com')
- db.session.add(user)
- db.session.commit()
-
- # 查询数据
- users = User.query.all()
- for user in users:
- print(user.username)
-
- # 更新数据
- user = User.query.filter_by(username='john').first()
- user.email = 'newemail@example.com'
- db.session.commit()
-
- # 删除数据
- user = User.query.filter_by(username='john').first()
- db.session.delete(user)
- db.session.commit()
-
-
- if __name__ == '__main__':
- app.run(debug=True)
在开发时,以删除表再重建的方式更新数据库简单直接,但明显的缺陷是会丢掉数据库中的所有数据。在生产环境下,没有人想把数据都删除掉,这时需要使用数据库迁移工具来完成这个工作。SQLAlchemy的开发者Michael Bayer写了一个数据库迁移工作—Alembic来帮助我们实现数据库的迁移,数据库迁移工具可以在不破坏数据的情况下更新数据库表的结构。蒸馏器(Alembic)是炼金术士最重要的工具,要学习SQL炼金术(SQLAlchemy),当然要掌握蒸馏器的使用。
扩展 Flask-Migrate 继承了 Alembic,提供了一些 flask 命令来简化迁移工作,可以使用它来迁移数据库。
- from flask import Flask
- from flask import render_template
- from flask_sqlalchemy import SQLAlchemy
- from flask_migrate import Migrate
-
- app = Flask(__name__)
- SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://user:passwd@host/my_db'
- app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
-
- db = SQLAlchemy(app)
- Migrate(app, db)
-
-
- class User(db.Model):
- __tablename__ = 'users'
-
- id = db.Column(db.Integer, primary_key=True)
- email = db.Column(db.String(250), unique=True, nullable=False)
- username = db.Column(db.String(250), unique=True, nullable=False)
- password = db.Column(db.String(250), nullable=False)
- login_time = db.Column(db.Integer)
-
- def __init__(self, username, password, email):
- self.username = username
- self.password = password
- self.email = email
-
- def __str__(self):
- return "Users(id='%s')" % self.id
-
-
- @app.route('/')
- def index():
- return 'Hello World'
-
-
- if __name__ == '__main__':
- app.run(debug=True)
Restful 运用于前后端分离
前端:app,小程序,pc页面
后端:没有页面,mvt:模型模板视图 去掉了t模板
mv:模型 视图
模型的使用:更原来的用法相同
视图:api构建视图
# 在创建app的函数中绑定API 等价于 api.init_app(app=app)
api = Api(app=app)
# 在创建app的函数中绑定db 等价于 db.init_app(app=app)
db = SQLAlchemy(api=蓝图对象)
视图中的类需要基础 flask_restful 中的 Resource
- from flask_restful import Resource
-
-
- class xxxApi(Resource):
- def get(self):
- pass
-
- def post(self):
- pass
api.add_resource(xxxApi,'/user')
- from flask import Flask
- from flask_sqlalchemy import SQLAlchemy
- from flask_restful import fields, marshal_with, Resource, Api
-
- app = Flask(__name__)
- app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///my_database.db'
- api = Api(app)
- db = SQLAlchemy(app)
-
-
- class User(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- username = db.Column(db.String(80), unique=True, nullable=False)
- email = db.Column(db.String(120), unique=True, nullable=False)
-
- def __repr__(self):
- return f'<User {self.username}>'
-
-
- # 格式化输出数据,相当于json的格式
- user = {
- 'id': fields.Integer,
- 'username': fields.String,
- 'password': fields.String
- }
-
-
- # 定义类视图
- class UserResource(Resource):
- # get请求处理
- # 在对应的api接口上添加配置:@marshal_with(user)
- @marshal_with(user) # user的json格式化输出
- def get(self):
- users = User.query.all()
- return users
-
-
- api.add_resource(UserResource, '/user')
- @app.route('/user')
- def user(): ----------->视图函数
- .....
- return response对象
增加 修改 删除 查询 按钮动作 都是自己在模板中写的
回顾 flask 路由路径上的参数解析使用:
路由的变量规则(解析路径上的参数)
string (缺省值)接收任何不包含斜杠的文本值
int 接收正整数
float 接收正浮点数
path 类似string,但是可以接收斜杠
UUID 接收UUID字符
route规则中如果传入了变量,那么被绑定的函数中也必须需要传入相应的参数
解析路径上的参数案例:
- @app.route('/<int:key>') # key是一个变量,默认就是字符串类型
- def city(key):
- return data.get(key)
restful:------->api-------->接口-------->资源------>uri
概述基本的 ResuFul 的建立:
class xxxApi(Response): -------视图类
def get(self):
pass
....http://127.0.0.1:5000/user 这个路径可以做的事:
get
post
put
delete
...
增加 修改 删除 查询 是通过请求方式完成的路径产生:
api.add_resource(xxxApi,'/user')
api.add_resource(xxxApi,'/goods')
api.add_resource(xxxApi,'/order')api 解析路径参数:http://127.0.0.1:5000/user/1
api 中的路径参数解析(与模板中的路径参数解析类型):
class UserGetIdResource(Resource):
@marshal_with(user)
def get(self, uid):
users = User.query.get(uid)
return users
api.add_resource(UserGetIdResource, '/user/<int:uid>')endpoint 的使用,便捷的反向解析出api
# 定义类视图
class UserResource(Resource):
def put(self):
print('endpoint的使用,反向解析出api:', url_for('all_user'))
return {'msg': '-------->ok'}api.add_resource(UserResource, '/user', endpoint='all_user')
参数解析:
1.使用 reqparse 对象进行传入的参数进行解析
parser = reqparse.RequestParser() # 创建解析对象
2.使用
parser.add_argument('username', type=str, required=True, help="必须输入账号", location=['form'])
args = parser.parse_args()
username = args.get('username')
案例:用于api中的数据被接收,我们需要验证或者过滤
# 参数解析
parser = reqparse.RequestParser(bundle_errors=True) # 解析对象
parser.add_argument('username', type=str, required=True, help="必须输入账号", location=['form'])
parser.add_argument('password', type=inputs.regex(r'^\d{6,12}$'), required=True, help="必须输入密码", location=['form'])
parser.add_argument('phone ', type=inputs.regex(r'^1[356789]\d{9}$'), location=['form'])
parser.add_argument('icon', required=True, type=FileStorage, location=['files'])
# From the request headers
parser.add_argument('Host', type=str, required=True, location=['headers'])#在对应请求中的使用
args = parser.parse_args()
username = args.get('username')
password = args.get('password')
phone = args.get('phone')
icon = args.get('icon')
host = args.get('Host')
概述:return data
主要:data 必须是 json 格式,默认的返回类型不是 json 格式,并且强行转换还会报错。解决方法如下。数据需要返回的格式类型
{
'aa':'haha',
'bb':[
{
'id':1,
'xxx':[
{},{},{}
]
}
]
}
如果直接返回不能有自定义的对象:User,Friend......
如果有,需要 marshal(),marshal_with() 帮助 JSON 的序列化进行转换.
@marshal_with(user_friend_fields)
def get(self,id):
.....
data={
xxx:xxx
xxx:xxx
'friends': friend_list # 直接是list,因为使用了@marshal_with(user_friend_fields)
}
return data
函数需要参数,参数就是最终数据输出的格式
参数:user_friend_fields,类型:dict类型
如:
user_fields = {
'id': fields.Integer,
'username': fields.String(default='匿名'),
'pwd': fields.String(attribute='password'),
'isDelete': fields.Boolean(attribute='isdelete')
}
user_friend_fields={
'username':fields.String,
'nums':fields.Integer,
'friends':fields.List(fields.Nested(user_fields))
}
3.fields.Nested 的作用
高级类型的数据转换
fields.Nested(fields.String) ---> ['aaa','bbb','bbbbv']
fields.Nested(user_fields) ---> user_fields是一个字典结构,将里边的每一个对象转 换成user_fields---->[user,user,user]
- import os
- from flask import Flask
- from flask import Blueprint, url_for
- from flask_restful import marshal_with, marshal
- from flask_restful import Resource, fields, reqparse, inputs
- from flask_restful import Api
- from flask_script import Manager
- from werkzeug.datastructures import FileStorage
- from flask_sqlalchemy import SQLAlchemy
- from flask_migrate import Migrate
-
- ##############################################################
- setting_conf = {}
- SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://user:passwd@host/my_db'
- # 蓝图的别名为user,看到/api 就是我们写的蓝图
- user_bp = Blueprint('user', __name__, url_prefix='/api')
- ##############################################################
-
- flask_app = Flask(__name__, template_folder='../templates', static_folder='../static')
- flask_app.config.from_object(setting_conf)
- flask_app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
- flask_app.register_blueprint(user_bp)
-
- # 将 SALAlchemy插件与app关联。等价于 db.init_app(app=flask_app)
- db = SQLAlchemy(flask_app)
- # 将api插件与app关联。等价于 api.init_app(app=flask_app)
- api = Api(app=flask_app)
- print(flask_app.url_map)
-
-
- class User(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- username = db.Column(db.String(20))
- password = db.Column(db.String(15))
- icon = db.Column(db.String(15))
- phone = db.Column(db.String(11))
-
-
- # 格式化输出数据,输出的json格式如下
- user = {
- 'id': fields.Integer,
- 'username': fields.String(20),
- 'password': fields.String(15)
- }
-
- user_fields = {
- 'id': fields.Integer,
- 'username': fields.String(default='匿名'),
- 'pwd': fields.String(attribute='password'),
- 'isDelete': fields.Boolean(attribute='isdelete')
- }
-
- user_friend_fields = {
- 'username': fields.String,
- 'nums': fields.Integer,
- 'friends': fields.List(fields.Nested(user_fields))
- }
-
- # 参数解析
- parser = reqparse.RequestParser(bundle_errors=True) # 解析对象
- parser.add_argument('username', type=str, required=True, help="必须输入账号", location=['form'])
- parser.add_argument('password', type=inputs.regex(r'^\d{6,12}$'), required=True, help="必须输入密码", location=['form'])
- parser.add_argument('phone ', type=inputs.regex(r'^1[356789]\d{9}$'), location=['form'])
- parser.add_argument('icon', required=True, type=FileStorage, location=['files'])
- # From the request headers
- parser.add_argument('Host', type=str, required=True, location=['headers'])
-
-
- # 定义类视图
- class UserResource(Resource):
- # get请求处理
- @marshal_with(user) # user的json格式化输出
- def get(self):
- users = User.query.all()
- print(users)
- return users
-
- @marshal_with(user)
- def post(self):
- args = parser.parse_args()
- username = args.get('username')
- password = args.get('password')
- phone = args.get('phone')
- icon = args.get('icon')
- host = args.get('Host')
- print('host:', host)
- print('icon:', icon)
-
- # 创建user对象
- user_db_model = User()
- user_db_model.icon = icon
- user_db_model.username = username
- user_db_model.password = password
- user_db_model.phone = phone
- db.session.add(user_db_model)
- db.session.commit()
- return user_db_model
-
- def put(self):
- print('endpoint的使用,反向解析出api:', url_for('all_user'))
- return {'msg': '-------->ok'}
-
- def delete(self):
- return {'msg': '-------->delete'}
-
-
- class UserGetIdResource(Resource):
- @marshal_with(user)
- def get(self, uid):
- users = User.query.get(uid)
- return users
-
- def put(self, uid):
- pass
-
- def post(self, uid):
- pass
-
- def delete(self):
- pass
-
-
- class UserFriendResoruce(Resource):
- @marshal_with(user_friend_fields)
- def get(self, id):
- friends = Friend.query.filter(Friend.uid == id).all()
- user = User.query.get(id)
- friend_list = []
- for friend in friends:
- u = User.query.get(friend.fid)
- friend_list.append(u)
-
- # data = {
- # 'username': user.username,
- # 'nums': len(friends),
- # 'friends': marshal(friend_list, user_fields) # marshal(数据名, 结构名)
- # }
- data = {
- 'username': user.username,
- 'nums': len(friends),
- 'friends': friend_list # 直接是list,因为使用了@marshal_with(user_friend_fields)
- }
-
- return data
-
- def post(self):
- pass
-
-
- if __name__ == '__main__':
- api.add_resource(UserResource, '/user', endpoint='all_user')
- api.add_resource(UserGetIdResource, '/user/<int:uid>')
- api.add_resource(UserFriendResoruce, '/friend/<int:id>')
- # 搭建数据库
- # migrate = Migrate(app=flask_app, db=db)
- pass
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。