Python flask-restful 框架講解

1、簡介

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-RESTPlusFlask-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

2、快速入門

安裝:pip install flask-restful

簡單示例

一個最小的 Flask-RESTful API 像這樣:

from flask import Flask
from flask_restful import Resource, Apiapp = 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, Apiapp = 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, Apiapp = 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 OKreturn {'task': 'Hello world'}class Todo2(Resource):def get(self):# Set the response code to 201return {'task': 'Hello world'}, 201class Todo3(Resource):def get(self):# Set the response code to 201 and return custom headersreturn {'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

端點 ( Endpoints )

很多時候,在一個 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, Apiapp = 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 OKreturn {'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, Resourceapp = 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 OKreturn {'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, Apiapp = 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_idself.task = task# This field will not be sent in the responseself.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, Resourceapp = 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 '', 204def put(self, todo_id):args = parser.parse_args()task = {'task': args['task']}TODOS[todo_id] = taskreturn task, 201# TodoList
# shows a list of all todos, and lets you POST to add new tasks
class TodoList(Resource):def get(self):return TODOSdef post(self):args = parser.parse_args()todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1todo_id = 'todo%i' % todo_idTODOS[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"
? ? }
}

使用 gunicorn、異步

安裝: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 WSGIServermonkey.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

flask_restful.marshal 過濾 數據

示例:

from flask import Flask
from flask_restful import Api, Resource, fields, marshalapp = 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_dataapi.add_resource(HelloWorld, '/hello', '/', '/world')if __name__ == '__main__':app.run(debug=True)

flask_sqlalchemy

: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 SQLAlchemyapp = 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)

Flask_migrate

在開發時,以刪除表再重建的方式更新數據庫簡單直接,但明顯的缺陷是會丟掉數據庫中的所有數據。在生產環境下,沒有人想把數據都刪除掉,這時需要使用數據庫遷移工具來完成這個工作。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 Migrateapp = Flask(__name__)
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://user:passwd@host/my_db'
app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URIdb = 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 = usernameself.password = passwordself.email = emaildef __str__(self):return "Users(id='%s')" % self.id@app.route('/')
def index():return 'Hello World'if __name__ == '__main__':app.run(debug=True)

3、總結:整體流程

Restful 運用于前后端分離

前端:app,小程序,pc頁面
后端:沒有頁面,mvt:模型模板視圖 去掉了t模板
mv:模型 視圖
模型的使用:更原來的用法相同
視圖:api構建視圖

創建 api 對象在exts擴展包中

# 在創建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 Resourceclass xxxApi(Resource):def get(self):passdef post(self):pass

給 app 綁定 api 視圖(view中完成)

api.add_resource(xxxApi,'/user')

格式化輸出 ( 都在view中完成 )

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_restful import fields, marshal_with, Resource, Apiapp = 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 usersapi.add_resource(UserResource, '/user')

路由

flask?中路由的寫法

@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?中路由寫法

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')

數據傳入(進)( request?)

參數解析:

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')

數據返回(出)( response )

概述:return data
主要:data 必須是 json 格式,默認的返回類型不是 json 格式,并且強行轉換還會報錯。解決方法如下。數據需要返回的格式類型

? ? {
? ? ? ? 'aa':'haha',
? ? ? ? 'bb':[
? ? ? ? ? ? {
? ? ? ? ? ? 'id':1,
? ? ? ? ? ? 'xxx':[
? ? ? ? ? ? ? ? ? ? {},{},{}
? ? ? ? ? ? ? ? ]
? ? ? ? ? ? }
? ? ? ? ]
? ? }

如果直接返回不能有自定義的對象:User,Friend......
如果有,需要 marshal(),marshal_with() 幫助 JSON 的序列化進行轉換.

  • 1. marshal(對象,對象的fields格式) #對象的fields格式是指字典的輸出格式 marshal([對象,對象],對象的fields格式)
  • 2. marshal_with() 作為裝飾器,修飾你的請求方法

?@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 = iconuser_db_model.username = usernameuser_db_model.password = passworduser_db_model.phone = phonedb.session.add(user_db_model)db.session.commit()return user_db_modeldef 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 usersdef put(self, uid):passdef post(self, uid):passdef delete(self):passclass 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 datadef post(self):passif __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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/34927.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/34927.shtml
英文地址,請注明出處:http://en.pswp.cn/news/34927.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sentinel簡單使用

核心demo&#xff1a; 1 引入依賴: <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.0</version> </dependency>2 核心代碼&#xff1a; 3 限流保護代碼&#xff1a;…

【Megatron-DeepSpeed】張量并行工具代碼mpu詳解(四):張量并行版Embedding層及交叉熵的實現及測試

相關博客 【Megatron-DeepSpeed】張量并行工具代碼mpu詳解(四)&#xff1a;張量并行版Embedding層及交叉熵的實現及測試 【Megatron-DeepSpeed】張量并行工具代碼mpu詳解(三)&#xff1a;張量并行層的實現及測試 【Megatron-DeepSpeed】張量并行工具代碼mpu詳解(一)&#xff1a…

【HarmonyOS】@ohos.request 上傳下載的那些事兒

【關鍵字】 ohos.request、上傳下載? 【寫在前面】 在進行HarmonyOS應用開發時&#xff0c;可能需要進行上傳或下載文件功能開發&#xff0c;本文章主要進行上傳下載相關功能介紹和一些注意事項及FAQ。 【上傳開發步驟】 步驟1&#xff1a;上傳下載接口需要申請ohos.permis…

GitOps 與 DevOps:了解關鍵差異,為企業做出最佳選擇

在軟件開發領域&#xff0c;GitOps 和 DevOps 是加強協作和實現軟件交付流程自動化的重要技術。雖然這兩種模式都旨在提高軟件開發生命周期的效率&#xff0c;但它們的核心原則和實施方式卻各不相同。 本篇文章將幫助您了解 GitOps 和 DevOps 之間的差異、它們的工作流程&am…

新知識:Monkey 改進版之 App Crawler

原生Monkey 大家知道Monkey是Android平臺上進行壓力穩定性測試的工具&#xff0c;通過Monkey可以模擬用戶觸摸屏幕、滑動、按鍵等偽隨機用戶事件來對設備上的程序進行壓力測試。而原生的Android Monkey存在一些缺陷&#xff1a; 事件太過于隨機&#xff0c;測試有效性大打折扣…

【2023新教程】樹莓派4B開機啟動-樹莓派第一次啟動-樹莓派不使用顯示器啟動-樹莓派從購買到啟動一步一步完全版!

背景 閑來無事&#xff0c;在咸魚上買了一個樹莓派4B。買來配件都十分齊全&#xff0c;于是就想著啟動來測試一下。下面是樹莓派無顯示器第一次啟動的全過程&#xff0c;包含安裝系統。 網上的教程大多需要額外使用顯示器、鼠標、鍵盤之類的外設。然而&#xff0c;樹莓派本身就…

從一到無窮大 #10 討論 Apache IoTDB 大綜述中看到的優勢和不足點

本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。 本作品 (李兆龍 博文, 由 李兆龍 創作)&#xff0c;由 李兆龍 確認&#xff0c;轉載請注明版權。 文章目錄 引言問題定義新技術數據模型schemalessTsfile設計雙MemTable高級可擴展查詢其他 IotD…

免費開源的多種人工智能項目,比如:訓練一個模型,讓人工智能玩王者榮耀

免費開源的多種人工智能項目&#xff0c;比如&#xff1a;訓練一個模型&#xff0c;讓人工智能玩王者榮耀。 全文大綱 PULSE - 該開源項目可以通過給圖片增加像素點來實現去馬賽克或高清化。 Depix - 給打了馬賽克的文字去碼。 TecoGAN - 給視頻去馬賽克或者進行超分辨率。 Sk…

計算機網絡-專業術語

計算機網絡-專業術語 實體 實體:任何可發送或接收信息的硬件或軟件進程 對等實體:收發雙方相同層次中的實體 協議 控制兩個對等實體進行邏輯通信的規則的集合 協議三要素 語法 定義所交換的信息的格式 是用戶數據與控制信息的結構和格式 語義 定義收發雙方所需要完成的操作…

go 切換代理

常用 $ go env -w GO111MODULEon $ go env -w GOPROXYhttps://goproxy.cn,direct 切換成阿里云 go env -w GOPROXYhttps://mirrors.aliyun.com/goproxy/,direct 很多需要切換到阿里云才行 刪除 $ go env -u GOPROXY 查看 $ go env 或者 go env list go get 出錯的時候 …

Kotlin 基礎教程一

Kotlin 基本數據類型 Java | Kotlin byte Byte short Short int Int long Long float Float double Double boolean Boolean c…

一 、個性化電商廣告推薦系統介紹

一 個性化電商廣告推薦系統介紹 1.1 數據集介紹 Ali_Display_Ad_Click是阿里巴巴提供的一個淘寶展示廣告點擊率預估數據集 數據集來源&#xff1a;天池競賽 原始樣本骨架raw_sample 淘寶網站中隨機抽樣了114萬用戶8天內的廣告展示/點擊日志&#xff08;2600萬條記錄&#xff…

LangChain-ChatGLM在WIndows10下的部署

LangChain-ChatGLM在WIndows10下的部署 參考資料 1、LangChain ChatGLM2-6B 搭建個人專屬知識庫中的LangChain ChatGLM2-6B 構建知識庫這一節&#xff1a;基本的邏輯和步驟是對的&#xff0c;但要根據Windows和現狀做很多調整。 2、沒有動過model_config.py中的“LORA_MOD…

validation之自定義注解@Constraint

前言&#xff1a; 首先&#xff0c;接口參數校驗應該都不陌生&#xff0c;大部分應該都會借助javax.validation進行快捷校驗&#xff0c;一般都是在入參字段上添加NotNull、NotEmpty等&#xff0c;對于一些特殊的入參校驗邏輯&#xff0c;可能不是很適用&#xff0c;現在介紹一…

【ECMAScript】ES6-ES11學習筆記

文章目錄 注意事項1.聲明變量2.定義常量3.解構賦值4.模板字符串5.簡化對象寫法6.箭頭函數7.參數默認值8.rest參數9.擴展運算符10.Symbol11.生成器函數12.Promise基本語法13.集合set14.Map15.類class16.數值擴展17.對象私有屬性18.對象方法擴展19.js文件模塊化20.async和await21…

數據庫操作不再困難,MyBatis動態Sql標簽解析

系列文章目錄 MyBatis緩存原理 Mybatis的CachingExecutor與二級緩存 Mybatis plugin 的使用及原理 MyBatis四大組件Executor、StatementHandler、ParameterHandler、ResultSetHandler 詳解 MyBatisSpringboot 啟動到SQL執行全流程 數據庫操作不再困難&#xff0c;MyBatis動態S…

Neo4j之MATCH基礎

1】基本匹配和返回&#xff1a;查找所有節點和關系&#xff0c;返回節點的標簽和屬性。 MATCH (n) RETURN n;2】條件篩選&#xff1a;查找所有名為 "Alice" 的人物節點。 MATCH (person:Person {name: Alice}) RETURN person;3】關系查詢&#xff1a;查找所有和 &q…

Centos7.6 安裝mysql過程全記錄

在centos 7.6上 離線安裝mysql 的步驟&#xff0c;可參考下文&#xff1a; 一、查看當前MySQL的安裝情況并卸載 1. 查看當前MySQL的安裝情況 查找之前是否安裝了MySQL rpm -qa|grep -i mysql 2.卸載mysql 如果已經安裝mysql&#xff0c;則需要先停止MySQL&#xff0c;再刪除…

YOLOv5、YOLOv8改進:MobileViT:輕量通用且適合移動端的視覺Transformer

MobileViT: Light-weight, General-purpose, and Mobile-friendly Vision Transformer 論文&#xff1a;https://arxiv.org/abs/2110.02178 1簡介 MobileviT是一個用于移動設備的輕量級通用可視化Transformer&#xff0c;據作者介紹&#xff0c;這是第一次基于輕量級CNN網絡性…

LeetCode150道面試經典題--單詞規律(簡單)

1.題目 給定一種規律 pattern 和一個字符串 s &#xff0c;判斷 s 是否遵循相同的規律。 這里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每個字母和字符串 s 中的每個非空單詞之間存在著雙向連接的對應規律。 2.示例 pattern"abba" s "c…