Pregunta

Tengo una pregunta sobre la extensión de descanso del matraz.Recién comencé a usarlo y enfrenté un problema.Tengo flask-sqlalchemy entidades que están conectadas en una relación de muchos a uno y quiero que ese punto final tranquilo devuelva la entidad principal con todos sus hijos en json usando marshall.En mi caso, Set contiene muchos parámetros.Miré el matraz-reposado documentos pero no hubo ninguna explicación de cómo resolver este caso.

Parece que me falta algo obvio pero no puedo encontrar ninguna solución.Aquí está mi código:

# entities
class Set(db.Model):
    id = db.Column("id", db.Integer, db.Sequence("set_id_seq"), primary_key=True)
    title = db.Column("title", db.String(256))

    parameters = db.relationship("Parameters", backref="set", cascade="all")


class Parameters(db.Model):
    id = db.Column("id", db.Integer, db.Sequence("parameter_id_seq"), primary_key=True)
    flag = db.Column("flag", db.String(256))
    value = db.Column("value", db.String(256))
    set_id = db.Column("set_id", db.Integer, db.ForeignKey("set.id"))


# marshallers

from flask.ext.restful import fields

parameter_marshaller = {
    "flag": fields.String,
    "value": fields.String
}

set_marshaller = {
    'id': fields.String,
    'title': fields.String,
    'parameters': fields.List(fields.Nested(parameter_marshaller))
}

# endpoint    

class SetApi(Resource):

    @marshal_with(marshallers.set_marshaller)
    def get(self, set_id):
        entity = Set.query.get(set_id)
        return entity


restful_api = Api(app)
restful_api.add_resource(SetApi, "/api/set/<int:set_id>")

Ahora cuando llamo /api/set/1 Recibo un error del servidor:

TypeError: 'Set' object is unsubscriptable

Entonces necesito una manera de definir correctamente set_marshaller y ese punto final devuelve este json:

{
  "id": : "1",
  "title": "any-title",
  "parameters": [
       {"flag": "any-flag", "value": "any-value" },
       {"flag": "any-flag", "value": "any-value" },
       .....
   ]
}

Agradezco cualquier ayuda.

¿Fue útil?

Solución

Yo mismo encontré la solución a ese problema.

Después de jugar con flask-restful Descubrí que cometí algunos errores:

En primer lugar set_marshaller debería verse así:

blob_marshaller = {
    'id': fields.String,
    'title': fields.String,
    'parameters': fields.Nested(parameter_marshaller)
}

El marshaller inquieto puede manejar el caso si el parámetro es una lista y dirigirse a json lista.

Otro problema fue que en API Set los parámetros tienen una carga diferida, por lo que cuando intento ordenar Set obtengo KeyError: 'parameters', entonces necesito cargar explícitamente parámetros como este:

class SetApi(Resource):

     @marshal_with(marshallers.set_marshaller)
     def get(self, set_id):
        entity = Set.query.get(set_id)
        entity.parameters # loads parameters from db
        return entity

U otra opción es cambiar la relación del modelo:

parameters = db.relationship("Parameters", backref="set", cascade="all" lazy="joined")

Otros consejos

Esta es una adición a Zygimantas's respuesta:

Estoy usando Flask-RESTful y esta es una solución para la carga de propiedades anidadas.

Puede pasar un invocable al decorador mariscal:

class OrgsController(Resource):
    @marshal_with(Organization.__json__())
    def get(self):
        return g.user.member.orgs

Luego actualice los modelos para devolver los campos de recursos de su propia entidad.Por lo tanto, las entidades anidadas devolverán relativamente los campos de recursos de su entidad.

class Organization(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    ...

    @staticmethod
    def __json__(group=None):
        _json = {
            'id': fields.String,
            'login': fields.String,
            'description': fields.String,
            'avatar_url': fields.String,
            'paid': fields.Boolean,
        }

        if group == 'flat':
            return _json

        from app.models import Repository
        _json['repos'] = fields.Nested(Repository.__json__('flat'))

        return _json

class Repository(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    owner_id = db.Column(db.Integer, db.ForeignKey('organization.id'))
    owner = db.relationship('Organization', lazy='select', backref=db.backref('repos', lazy='select'), foreign_keys=[owner_id])
    ...

    @staticmethod
    def __json__(group=None):
        _json = {
            'id': fields.String,
            'name': fields.String,
            'updated_at': fields.DateTime(dt_format='iso8601'),
        }

        if group == 'flat':
            return _json

        from app.models import Organization
        _json['owner'] = fields.Nested(Organization.__json__('flat'))

        return _json

Esto proporciona la representación que estoy buscando y respeta la carga diferida:

[
    {
        "avatar_url": "https://avatars.githubusercontent.com/u/18945?v=3",
        "description": "lorem ipsum.",
        "id": "1805",
        "login": "foobar",
        "paid": false,
        "repos":
            [
                {
                    "id": "9813",
                    "name": "barbaz",
                    "updated_at": "2014-01-23T13:51:30"
                },
                {
                    "id": "12860",
                    "name": "bazbar",
                    "updated_at": "2015-04-17T11:06:36"
                }
            ]
    }
]

Me gusta

1) cómo este enfoque me permite definir mis campos de recursos por entidad y está disponible para todas mis rutas de recursos en la aplicación.

2) cómo el argumento del grupo me permite personalizar la representación como desee.Aquí solo tengo "plano", pero cualquier lógica se puede escribir y transmitir a objetos anidados más profundos.

3) las entidades solo se cargan según sea necesario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top