1. Introducción
Django y Flask siempre han sido la primera opción para desarrollar la Web con Python, y el microkernel de Flask es más adecuado para el marco actual de microservicios nativos de la nube. Pero Flask es solo un pequeño motor web, por lo que debemos ampliar Flask para hacerlo más potente.
Explicación detallada del marco del matraz de Python: https://blog.csdn.net/shifengboy/article/details/114274271
Matraz-RESTful
Flask-RESTful es el líder entre las extensiones de Flask. Agrega soporte para la construcción rápida de API RESTful y encapsula Flask para que sea más fácil, rápido y conveniente desarrollar API RESTful.
GitHub: https://github.com/flask-restful/flask-restful
Documentación en inglés: https://flask-restful.readthedocs.io/en/latest/
Documentación en chino: http://www.pyndoc.com/Flask -Sosegado/
Matraz-RESTPlus
Sabemos que Flask-RESTful es una extensión de Flask y Flask-RESTPlus es una extensión de Flask-RESTful, que es totalmente compatible con Flask-RESTful y tiene soporte de documentos de interfaz mejorado.
Flask-RESTPlus proporciona un conjunto coherente de decoradores y herramientas para describir los parámetros y objetos requeridos por la API del documento, y usa Swagger para analizarlos en documentos de interfaz correctos.
GitHub: https://github.com/noirbizarre/flask-restplus
Documentos: https://flask-restplus.readthedocs.io/en/latest/
Matraz-RESTX
Dado que ya existe un Flask-RESTPlus perfecto, ¿por qué necesita Flask-RESTX?
De hecho, he estado usando Flask-RESTPlus durante mucho tiempo, ¡pero lo triste es que el autor lo perdió! Así es, está perdido en el sentido físico. Los miembros del equipo del proyecto Flask-RESTPlus no pueden encontrarlo. Para continuar manteniendo este proyecto, el equipo solo puede abrir otra rama para continuar Flask-RESTPlus. El proyecto es Matraz-RESTX.Flask-RESTX
Totalmente compatibleFlask-RESTPlus
,Flask-RESTPlus
los problemas acumulados en el proyectoBUG
seFlask-RESTX
heredan por completo y el equipo de la comunidad mantiene y resume activamente,GitHub: https://github.com/python-restx/flask-restx
Documentos: https://flask-restx.readthedocs.io/en/latest/
API rápida
FastAPI es un nuevo marco web independiente de Flask. Aunque puede ver muchas sombras de Flask y extensiones relacionadas, también se ha convertido en uno de los marcos web que no se pueden ignorar, y FastAPI también es conocido como uno de los marcos Python más rápidos.
GitHub: https://github.com/tiangolo/fastapi
Documentos: https://fastapi.tiangolo.com
2. Inicio rápido
Instalación: pip install matraz-reposado
ejemplo sencillo
Una API Flask-RESTful mínima se ve así:
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)
Guarde el código anterior como api.py y ejecútelo en su intérprete de Python. Tenga en cuenta que hemos habilitado el modo de depuración de Flask , que proporciona recarga de código y mejores mensajes de error. El modo de depuración nunca debe usarse en un entorno de producción.
$ python api.py
* Se ejecuta en http://127.0.0.1:5000/
Ahora abra una nueva ventana de línea de comando y use curl para probar su API:
$ curl http://127.0.0.1:5000/
{"hola": "mundo"}
enlace "recurso (vista) y ruta"
La clase en la vista necesita heredar el Recurso en matraz_restful
Los principales componentes básicos proporcionados por Flask-RESTful son los recursos. Los recursos se construyen sobre las vistas conectables de Flask, lo que permite un fácil acceso a múltiples métodos HTTP simplemente definiendo métodos en el recurso . Un recurso CRUD básico para una aplicación de tareas pendientes se ve así:
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)
Puedes probar esto:
$ curl http://localhost:5000/todo1 -d "data=Recordar la leche" -X PUT
{"todo1": "Recordar la leche"}
$ curl http://localhost:5000/todo1
{"todo1": "Recuerda la leche"}
$ curl http://localhost:5000/todo2 -d "data=Cambiar mis pastillas de freno" -X PUT
{"todo2": "Cambiar mis pastillas de freno"}
$ curl http://localhost:5000/ todo2
{"todo2": "Cambiar mis pastillas de freno"}
O desde el shell de python si tiene instalada la biblioteca de solicitudes:
>>> de solicitudes import put, get
>>> put('http://localhost:5000/todo1', data={'data': 'Recordar la leche'}).json() {
u'todo1': u'Recuerda la leche'}
>>> get('http://localhost:5000/todo1').json()
{u'todo1': u'Recuerda la leche'}
>>> put('http:/ /localhost:5000/todo2', data={'data': 'Cambiar mis pastillas de freno'}).json() {
u'todo2': u'Cambiar mis pastillas de freno'}
>>> get('http://localhost :5000/todo2').json()
{u'todo2': u'Cambiar mis pastillas de freno'}
Flask-RESTful admite múltiples tipos de valores de retorno de los métodos de visualización. Al igual que con Flask, puede devolver cualquier iterador, que se convertirá en una respuesta que contenga el objeto de respuesta de Flask original. Flask-RESTful también admite múltiples valores de retorno para establecer códigos de respuesta y encabezados de respuesta, de la siguiente manera:
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)
prueba
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
Puntos finales
Muchas veces, en una API, sus recursos tendrán varias URL. Se pueden pasar varias direcciones URL al método add_resource() en el objeto Api. Cada uno se enrutará a Recurso
api.add_resource(HolaMundo,
'/',
'/hola')
También puede especificar parámetros de punto final para sus métodos de recursos.
api.add_resource(All,
'/all/<int:all_id>', endpoint='all_ep');
ejemplo
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)
prueba
rizo http://127.0.0.1:5000/
rizo http://127.0.0.1:5000/hola
rizo http://127.0.0.1:5000/todo/1
rizo http://127.0.0.1:5000/todo/ 2
Análisis de parámetros
Aunque Flask proporciona un fácil acceso a los datos de la solicitud (como cadenas de consulta o datos codificados en formularios POST), la validación de los datos del formulario aún puede ser una molestia. Flask-RESTful tiene soporte incorporado para validar datos de solicitudes usando una biblioteca como argparse .
ejemplo
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)
prueba
curl -d 'tasa=100' http://127.0.0.1:5000/todos
curl -d 'tasa=foo' http://127.0.0.1:5000/todos
A diferencia del módulo argparse, reqparse.RequestParser.parse_args() devuelve un diccionario de Python en lugar de una estructura de datos personalizada.
El módulo de entrada proporciona muchas funciones de conversión de uso común, como entradas.fecha() y entradas.url().
Llamar a parse_args con strict=True garantiza que se produzca un error si la solicitud contiene argumentos que su analizador no define.
argumentos = analizador.parse_args(estricto=Verdadero)
curl -d 'tasa2=foo' http://127.0.0.1:5000/todos
formato de datos
De forma predeterminada, todos los campos se representarán tal cual en su iteración de devolución. Aunque puede parecer un gran trabajo cuando solo se trata de estructuras de datos de Python, puede ser frustrante y aburrido cuando realmente se trata de ellas. Para resolver este problema, Flask-RESTful proporciona un módulo de campos y un decorador marshal_with(). Al igual que Django ORM y WTForm, puede usar el módulo de campos para formatear estructuras en sus respuestas.
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)
El ejemplo anterior toma un objeto python y lo prepara para la serialización. El decorador marshal_with() se aplicará a las transformaciones descritas por resource_fields. El único campo extraído del objeto es tarea. El campo fields.Url es un campo especial que acepta un nombre de punto final como argumento y genera una URL para ese punto final en la respuesta. Muchos de los tipos de campos que necesitará ya están incluidos. Consulte la guía de campos para obtener una lista completa.
$ curl http://127.0.0.1:5000/todo
{ "tarea": "Recuerda la leche", "uri": "/todo" }
ejemplo completo
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)
prueba
curl http://localhost:5000/todos obtener lista
curl http://localhost:5000/todos/todo3 obtener una sola tarea
eliminar una tarea
$ curl http://localhost:5000/todos/todo2 -X DELETE -v
* Trying ::1...
* TCP_NODELAY set
* Conexión fallida
* conexión a ::1 puerto 5000 fallida: Conexión rechazada
* Trying 127.0.0.1. ..
* TCP_NODELAY establecido
* Conectado a localhost (127.0.0.1) puerto 5000 (#0)
> DELETE /todos/todo2 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Aceptar: */ *
>
* HTTP 1.0, supone cerrar después del cuerpo
< HTTP/1.0 204 SIN CONTENIDO
< Tipo de contenido: aplicación/json
< Servidor: Werkzeug/1.0.1 Python/3.9.2
< Fecha: sábado, 06 de marzo de 2021 03:29: 33 GMT
<
* Cerrar conexión 0
añadir una nueva tarea
$ curl http://localhost:5000/todos -d "tarea=algo nuevo" -X POST -v
Nota: El uso innecesario de -X o --request, POST ya se infiere.
* Intentando ::1...
* TCP_NODELAY establecido
* Conexión fallida
* conexión a ::1 puerto 5000 fallida: Conexión rechazada
* Intentando 127.0.0.1...
* TCP_NODELAY establecido
* Conectado al localhost (127.0.0.1) puerto 5000 (# 0)
> POST /todos HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Aceptar: */*
> Content-Length: 18
> Content-Type: application/x-www-form- urlencoded
>
* carga completamente enviada: 18 de 18 bytes
* HTTP 1.0, suponga que se cierra después del cuerpo
< HTTP/1.
< Tipo de contenido: application/json
< Longitud del contenido: 32
< Servidor: Werkzeug/1.0.1 Python/3.9.2
< Fecha: sábado, 06 de marzo de 2021 03:31:02 GMT
<
{ "tarea": "algo nuevo " } * Cerrar conexión 0
actualizar una tarea
$ curl http://localhost:5000/todos/todo3 -d "tarea=algo diferente" -X PUT -v
* Trying ::1...
* TCP_NODELAY set
* Conexión fallida
* conexión a ::1 puerto 5000 fallida: Conexión rechazada
* Probando 127.0.0.1...
* TCP_NODELAY configurado
* Conectado a localhost (127.0.0.1) puerto 5000 (#0)
> PUT /todos/todo3 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/ 7.64.1
> Aceptar: */*
> Longitud del contenido: 24
> Tipo de contenido: application/x-www-form-urlencoded
>
* cargar completamente enviado: 24 de 24 bytes
* HTTP 1.0, asumir cerrar después del cuerpo
< HTTP/1.0 201 CREADO
<Tipo de contenido: aplicación/json
< Longitud del contenido: 38
< Servidor: Werkzeug/1.0.1 Python/3.9.2
< Fecha: sábado, 06 de marzo de 2021 03:32:44 GMT
<
{ "tarea": "algo diferente" } * Cerrar conexión 0
obtener la lista más reciente
$ curl http://localhost:5000/todos
{ "todo1": { "tarea": "crear una API" }, "todo3": { "tarea": "algo diferente" }, "todo4": { "tarea ": "algo nuevo" } }
Usando gunicorn, asíncrono
Instalación: pip install gunicorn
Un ejemplo simple de gunicorn implementando un proyecto de matraz: 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
matraz_restful.marshal filtrar datos
Ejemplo:
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': '[email protected]',
}
# 定义字段格式和过滤器
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)
matraz_sqlalchemy
:https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/
Flask-SQLAlchemy es una extensión de SQLAlchemy para usar con Flask, que proporciona métodos y herramientas convenientes para usar SQLAlchemy para operaciones de bases de datos en aplicaciones de Flask.
Instale la extensión de matraz_sqlalchemy: pip install matraz_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='[email protected]')
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 = '[email protected]'
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
Durante el desarrollo, es sencillo actualizar la base de datos eliminando tablas y reconstruyéndolas, pero el inconveniente obvio es que se perderán todos los datos de la base de datos. En un entorno de producción, nadie quiere eliminar todos los datos. En este momento, debe usar una herramienta de migración de base de datos para completar este trabajo. El desarrollador de SQLAlchemy, Michael Bayer, escribió un trabajo de migración de base de datos: Alembic para ayudarnos a realizar la migración de la base de datos. La herramienta de migración de la base de datos puede actualizar la estructura de la tabla de la base de datos sin destruir los datos. Alambique es la herramienta más importante para los alquimistas.Para aprender SQL Alchemy, por supuesto, debe dominar el uso de alambique.
Extended Flask-Migrate hereda Alembic y proporciona algunos comandos de matraz para simplificar el trabajo de migración, que se pueden usar para migrar la base de datos.
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)
3. Resumen: proceso general
Restful se aplica a la separación de front-end y back-end
Front-end: aplicación, subprograma, página de PC
Back-end: sin página, mvt: la vista de plantilla del modelo elimina la plantilla t
mv: vista
del modelo Uso del modelo: igual que el uso original
Vista: vista de compilación de api
Cree un objeto api en el paquete de extensión exts
# Vincular la API en la función de creación de la aplicación, que es equivalente a api.init_app(app=app)
api = Api(aplicación=aplicación)
# Vincular db en la función de crear una aplicación es equivalente a db.init_app(app=app)
db = SQLAlchemy(api=blueprint object)
definir vista
La clase en la vista necesita el Recurso en la base Flash_restful
from flask_restful import Resource
class xxxApi(Resource):
def get(self):
pass
def post(self):
pass
Vincule la vista de API a la aplicación (completada en la vista)
api.add_resource(xxxApi,'/usuario')
Salida formateada (todo hecho a la vista)
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')
enrutamiento
Cómo escribir rutas en matraz
@app.route('/user')
def user(): ----------->视图函数
.....
return response对象
Usted mismo escribe en la plantilla las acciones de agregar, modificar y eliminar botones de consulta.
Revise el análisis de parámetros en la ruta de enrutamiento del matraz:
Reglas variables para el enrutamiento (parámetros de análisis en la ruta)
cadena (predeterminada) acepta cualquier valor de texto que no contenga una barra inclinada
int acepta un entero positivo
flotante acepta una ruta de número de coma flotante positiva
similar a la cadena, pero puede aceptar barras inclinadas
UUID acepta caracteres UUID
regla de ruta Si se pasa una variable, la función enlazada también debe pasar el parámetro correspondiente
Analizando el caso del parámetro en la ruta:
@app.route('/<int:key>') # key是一个变量,默认就是字符串类型
def city(key):
return data.get(key)
Enrutamiento en descanso
tranquilo: ------->api------->interfaz------->recurso------>uri
Para delinear la configuración básica de ResuFul:
class xxxApi(Respuesta): ------- ver class
def get(self):
pass
....http://127.0.0.1:5000/user Qué puede hacer esta ruta:
obtener
publicación
poner
eliminar
...
agregar modificar eliminar la consulta se realiza por solicitudValor predeterminado:
api.add_resource(xxxApi,'/user')
api.add_resource(xxxApi,'/goods')
api.add_resource(xxxApi,'/order');Parámetros de ruta de análisis de API: http://127.0.0.1:5000/user/1
Análisis de parámetros de ruta en API (con el tipo de análisis de parámetros de ruta en la plantilla):
class UserGetIdResource(Resource):
@marshal_with(user)
def get(self , uid):
usuarios = User.query.get(uid)
devolver usuarios
api.add_resource(UserGetIdResource, '/user/<int:uid>')El uso de punto final, análisis inverso conveniente para api
# Definir vista de clase
class UserResource(Resource):
def put(self):
print('uso de punto final, api de análisis inverso:', url_for('all_user'))
return {'msg': '----- --- >ok'}api.add_resource(UserResource, '/usuario', punto final='todos los_usuarios')
Datos entrantes (en) (solicitud)
Análisis de parámetros:
1. Use el objeto reqparse para analizar los parámetros entrantes
analizador = reqparse.RequestParser() # crear objeto de análisis
2. Use
parser.add_argument('username', type=str, required=True, help="Debe ingresar un número de cuenta", location=['form']) args = parser.parse_args() nombre de usuario
=
args.get ('nombre de usuario')
Caso: se reciben los datos utilizados en la api, necesitamos verificar o filtrar
# 参数解析
parser = reqparse.RequestParser(bundle_errors=True) # 解析对象
parser.add_argument('username', type=str, required=True, help="必须输入账号", location=['form']) analizador
. add_argument('contraseña', tipo=inputs.regex(r'^\d{6,12}$'), requerido=Verdadero, ayuda="必须输入密码", ubicación=['formulario']) analizador.add_argument
( 'teléfono', tipo=inputs.regex(r'^1[356789]\d{9}$'), ubicación=['formulario'])
parser.add_argument('icono', requerido=Verdadero, tipo=Almacenamiento de archivos, location=['files'])
# De los encabezados de solicitud
parser.add_argument('Host', type=str, required=True, location=['headers'])#Usar en la solicitud correspondiente
args = parser.parse_args()
nombre de usuario = args.get('nombre de usuario')
contraseña = args.get('contraseña')
teléfono = args.get('teléfono')
icono = args.get( ' icon')
host = argumentos.get('Host')
devolución de datos (salida) (respuesta)
Descripción general: datos de retorno
Principal: los datos deben estar en formato json, el tipo de retorno predeterminado no está en formato json y se informará un error si se fuerza la conversión. La solución es la siguiente. El tipo de formato en el que se deben devolver los datos.
{ 'aa':'jaja', 'bb':[ { 'id':1, 'xxx':[ {},{},{} ] } ] }
Si regresa directamente, no puede tener objetos personalizados: Usuario, Amigo...
Si los hay, se requiere marshal(), y marshal_with() ayuda a la serialización JSON para la conversión.
- 1. marshal (objeto, formato de campos del objeto) #El formato de campos del objeto se refiere al formato de salida del diccionario marshal ([objeto, objeto], formato de campos del objeto)
- 2. marshal_with() como decorador para modificar su método de solicitud
@marshal_with(user_friend_fields)
def get(self,id):
.....
data={ xxx:xxx xxx:xxx 'friends': friend_list # Es una lista directamente, porque se usa @marshal_with(user_friend_fields) } devolver datos
La función requiere parámetros, y los parámetros son el formato de la salida de datos final.Parámetro
: user_friend_fields, tipo: tipo de dictado
como:
campos_usuario = { 'id': campos.Integer, 'nombre de usuario': campos.String(predeterminado='匿名'), 'pwd': campos.String(atributo='contraseña'), 'isDelete': campos.Boolean(atributo ='isdelete') } user_friend_fields={ 'username':fields.String, 'nums':fields.Integer, 'friends':fields.List(fields.Nested(user_fields)) }
3. El rol de los campos. Anidados
Tipo avanzado de campos de conversión de datos.
Anidado (fields.String) ---> ['aaa', 'bbb', 'bbbbv']
campos. Anidado (user_fields) ---> user_fields es una estructura de diccionario, cada uno dentro de Convert an objeto a campos_usuario---->[usuario,usuario,usuario]
Código de muestra:
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