Explicación del marco de descanso del matraz de Python

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 compatible  Flask-RESTPlus, Flask-RESTPlus los problemas acumulados en el proyecto BUG se  Flask-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 solicitud

Valor 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

Supongo que te gusta

Origin blog.csdn.net/freeking101/article/details/132167978
Recomendado
Clasificación