简体   繁体   English

Flask-restful:将复杂对象编组为 json

[英]Flask-restful: marshal complex object to json

I have a question regarding flask restful extension.我有一个关于烧瓶宁静扩展的问题。 I'm just started to use it and faced one problem.我刚开始使用它并遇到一个问题。 I have flask-sqlalchemy entities that are connected many-to-one relation and I want that restful endpoint return parent entity with all its children in json using marshaller.我有连接多对一关系的flask-sqlalchemy实体,我希望这个宁静的端点使用marshaller在json返回父实体及其所有子实体。 In my case Set contains many parameters.就我而言, Set 包含许多参数。 I looked at flask-restful docs but there wasn't any explanation how to solve this case.我查看了flask-restful docs,但没有任何解释如何解决这种情况。

Seems like I'm missing something obvious but cannot figure out any solution.似乎我遗漏了一些明显的东西,但找不到任何解决方案。 Here is my 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>")

Now when i call /api/set/1 I get server error:现在,当我调用/api/set/1我收到服务器错误:

TypeError: 'Set' object is unsubscriptable

So I need a way to correctly define set_marshaller that endpoint return this json:所以我需要一种方法来正确定义 set_marshaller 端点返回这个 json:

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

I appreciate any help.我很感激任何帮助。

I found solution to that problem myself.我自己找到了解决这个问题的方法。

After playing around with flask-restful i find out that i made few mistakes:在玩过flask-restful我发现我犯了一些错误:

Firstly set_marshaller should look like this:首先set_marshaller应该是这样的:

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

Restless marshaller can handle case if parameter is list and marshals to json list.如果参数为列表并编组为json列表,则 Restless marshaller 可以处理大小写。

Another problem was that in API Set parameters has lazy loading, so when i try to marshall Set i got KeyError: 'parameters' , so I need explicitly load parameters like this:另一个问题是 API Set 参数有延迟加载,所以当我尝试编组 Set 我得到KeyError: 'parameters' ,所以我需要显式加载这样的参数:

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

Or another option is to change model relationship:或者另一种选择是更改模型关系:

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

This is an addition to Zygimantas 's answer :这是Zygimantas 回答的补充:

I'm using Flask-RESTful and this is a solution to the loading of the nested properties.我正在使用 Flask-RESTful,这是加载嵌套属性的解决方案。

You can pass a callable to the marshal decorator:您可以将可调用对象传递给 marshal 装饰器:

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

Then update the models to return the resource fields for its own entity.然后更新模型以返回其自身实体的资源字段。 Nested entities will thus return the resource fields for its entity relatively.因此,嵌套实体将相对返回其实体的资源字段。

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

This gives the representation I'm looking for, and honoring the lazy loading:这给出了我正在寻找的表示,并尊重延迟加载:

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

I like我喜欢

1) how this approach allows me to define my resource fields per entity and it is available to all my resource routes across the app. 1) 这种方法如何允许我为每个实体定义我的资源字段,并且它可用于我跨应用程序的所有资源路由。

2) how the group argument allows me to customise the representation however I desire. 2) group 参数如何允许我根据需要自定义表示。 I only have 'flat' here, but any logic can be written and passed down to deeper nested objects.我这里只有“平面”,但可以编写任何逻辑并将其传递给更深层的嵌套对象。

3) entities are only loaded as necessary. 3) 实体仅在必要时加载。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM