API Flask — создание вложенной группы ответов json по одной таблице полей

#python-3.x #rest #flask #flask-sqlalchemy

Вопрос:

У меня есть базовая настройка API, чтобы сделать базовую публикацию и получить ее из одной таблицы. Я хочу создать вложенный массив, сгруппировав его по типу force_element_type

model.py

 from db import db
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy import text as sa_text

class ForceElementModel(db.Model):
    __tablename__ = 'force_element'
    __table_args__ = {'schema': 'force_element'}

    force_element_id = db.Column(UUID(as_uuid=True), primary_key=True, server_default=sa_text("uuid_generate_v4()"))
    name = db.Column(db.String(100), nullable=False)
    force_element_type = db.Column(db.String(20), nullable=False)

    def __init__(self, name, force_element_type):
        self.name = name
        self.force_element_type = force_element_type

    def json(self):
        return {'name': self.name, 'force_element_type': self.force_element_type}

    @classmethod
    def find_by_name(cls, name):
        return cls.query.filter_by(name=name).first()  # simple TOP 1 select

    def save_to_db(self):  # Upserting data
        db.session.add(self)
        db.session.commit()  # Balla

    def delete_from_db(self):
        db.session.delete(self)
        db.session.commit()
 

resource.py

 from flask_restful import Resource, reqparse
#from flask_jwt import jwt_required
from models.force_element import ForceElementModel

class ForceElement(Resource):
    parser = reqparse.RequestParser()  # only allow price changes, no name changes allowed
    parser.add_argument('force_element_type', type=str, required=True, help='This field cannot be left blank')

    #@jwt_required()
    def post(self, name):
        if ForceElementModel.find_by_name(name):
            return {'message': "An Force Element with name '{}' already exists.".format(name)}, 400

        data = ForceElement.parser.parse_args()
        force_element = ForceElementModel(name, data['force_element_type'])

        try:
            force_element.save_to_db()
        except:
            return {"message": "An error occurred inserting the item."}, 500
        return force_element.json(), 201


class ForceElementList(Resource):
    #@jwt_required()
    def get(self):
        return {'force_elements': [force_element.json() for force_element in ForceElementModel.query.all()]}
    
class ForceElementType(Resource):
    #@jwt_required()
    def get(self):
 

Конечная точка GET с использованием списка ForceElementList возвращает

     {
    "force_elements": [
        {
            "name": "San Antonio",
            "force_element_type": "ship"
        },
        {
            "name": "Nimitz",
            "force_element_type": "ship"
        },
        {
            "name": "Nimitz- Starboard",
            "force_element_type": "Crew"
        },
        {
            "name": "Nimitz- Port",
            "force_element_type": "Crew"
        }
    ]
}
 

Я не знаю, как группировать по типу force_element_type и возвращать

 [
"ship": [
    {
        "name": "San Antonio",
        "force_element_id": "xxx1"
    },
    {
        "name": "Nimitz",
        "force_element_id": "xxx2"
    }],
"crew": [
    {
        "name": "Nimitz- Starboard",
        "force_element_id": "yyy1"
    },
    {
        "name": "Nimitz- Port",
        "force_element_id": "yyy2"
    }
]
 

]

Как мне создать эту отдельную точку?

Ответ №1:

Хорошо, я добрался туда, вот как я это сделал. Есть ли лучший способ?

Урок первый используйте онлайн-анализатор для проверки формата json, это то, к чему я на самом деле стремился, и квадратный тормоз в начале заставлял меня некоторое время чесать голову

 {
"ship": [
    {
        "name": "San Antonio",
        "force_element_id": "xxx1"
    },
    {
        "name": "Nimitz",
        "force_element_id": "xxx2"
    }],
"crew": [
    {
        "name": "Nimitz- Starboard",
        "force_element_id": "yyy1"
    },
    {
        "name": "Nimitz- Port",
        "force_element_id": "yyy2"
    }]
}
 

Этот код создает правильный формат для вывода

 class ForceElementType(Resource):
    #@jwt_required()
    def get(self):
        types = {}
        force_elements = ForceElementModel.query.order_by(ForceElementModel.force_element_type.desc()).all()
        for force_element in force_elements:
            nested = {'name':  force_element.name, 'force_element_id': str(force_element.force_element_id)}
            print(nested)
            if not force_element.force_element_type in types:
                types[force_element.force_element_type] = []
            types[force_element.force_element_type].append(nested)

        response = types