Question

J'ai une question concernant l'extension reposante du flacon.Je viens juste de commencer à l'utiliser et j'ai rencontré un problème.J'ai flask-sqlalchemy les entités qui sont connectées à une relation plusieurs-à-un et je veux que ce point de terminaison reposant renvoie une entité parent avec tous ses enfants dans json en utilisant marshaller.Dans mon cas, Set contient de nombreux paramètres.J'ai regardé un flacon reposant documents mais il n'y avait aucune explication sur la façon de résoudre cette affaire.

On dirait qu'il me manque quelque chose d'évident mais je n'arrive pas à trouver de solution.Voici mon code :

# 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>")

Maintenant, quand j'appelle /api/set/1 J'obtiens une erreur de serveur :

TypeError: 'Set' object is unsubscriptable

J'ai donc besoin d'un moyen de définir correctement set_marshaller pour que le point final renvoie ce json :

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

J'apprécie toute aide.

Était-ce utile?

La solution

J'ai trouvé moi-même la solution à ce problème.

Après avoir joué avec flask-restful je découvre que j'ai fait quelques erreurs :

Premièrement set_marshaller devrait ressembler à ceci :

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

Le marshaller agité peut gérer le cas si le paramètre est une liste et les marshals vers json liste.

Un autre problème était que dans l'API Set, les paramètres ont un chargement paresseux, donc quand j'essaie de marshall Set, j'obtiens KeyError: 'parameters', j'ai donc besoin de charger explicitement des paramètres comme celui-ci :

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 une autre option consiste à modifier la relation du modèle :

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

Autres conseils

Ceci est un ajout à Zygimantasc'est répondre:

J'utilise Flask-RESTful et c'est une solution pour le chargement des propriétés imbriquées.

Vous pouvez transmettre un appel au maréchal décorateur :

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

Mettez ensuite à jour les modèles pour renvoyer les champs de ressources de sa propre entité.Les entités imbriquées renverront ainsi les champs de ressources de leur entité de manière relative.

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

Cela donne la représentation que je recherche et honore le chargement paresseux :

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

J'aime

1) comment cette approche me permet de définir mes champs de ressources par entité et est disponible pour tous mes itinéraires de ressources à travers l'application.

2) comment l'argument de groupe me permet de personnaliser la représentation comme je le souhaite.Je n'ai que « plat » ici, mais n'importe quelle logique peut être écrite et transmise à des objets imbriqués plus profonds.

3) les entités ne sont chargées que si nécessaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top