Pergunta

Eu tenho uma pergunta sobre a extensão tranquila do frasco.Acabei de começar a usá-lo e enfrentei um problema.Eu tenho flask-sqlalchemy entidades que estão conectadas por uma relação muitos-para-um e quero que esse ponto final tranquilo retorne a entidade pai com todos os seus filhos em json usando marshaller.No meu caso, Set contém muitos parâmetros.Eu olhei para o frasco repousante documentos mas não houve nenhuma explicação de como resolver este caso.

Parece que estou perdendo algo óbvio, mas não consigo encontrar nenhuma solução.Aqui está o meu 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>")

Agora, quando eu ligo /api/set/1 Recebo um erro no servidor:

TypeError: 'Set' object is unsubscriptable

Então, preciso de uma maneira de definir corretamente set_marshaller para que o endpoint retorne este json:

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

Agradeço qualquer ajuda.

Foi útil?

Solução

Eu mesmo encontrei a solução para esse problema.

Depois de brincar com flask-restful descobri que cometi alguns erros:

Primeiramente set_marshaller deve ficar assim:

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

O empacotador inquieto pode lidar com o caso se o parâmetro for lista e empacotar para json lista.

Outro problema foi que na API Set os parâmetros têm carregamento lento, então quando tento empacotar Set recebo KeyError: 'parameters', então preciso carregar explicitamente 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

Ou outra opção é alterar o relacionamento do modelo:

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

Outras dicas

Este é um acréscimo Zygimantasde responder:

Estou usando Flask-RESTful e esta é uma solução para o carregamento das propriedades aninhadas.

Você pode passar um callable para o marechal decorador:

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

Em seguida, atualize os modelos para retornar os campos de recursos para sua própria entidade.As entidades aninhadas retornarão, portanto, os campos de recursos para sua entidade de forma relativa.

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

Isso fornece a representação que procuro e respeita o carregamento lento:

[
    {
        "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"
                }
            ]
    }
]

Eu gosto

1) como essa abordagem me permite definir meus campos de recursos por entidade e está disponível para todas as minhas rotas de recursos no aplicativo.

2) como o argumento do grupo me permite personalizar a representação da maneira que desejar.Eu só tenho 'flat' aqui, mas qualquer lógica pode ser escrita e transmitida para objetos aninhados mais profundos.

3) as entidades são carregadas apenas quando necessário.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top