首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >base_fields.Nested中的Flask-marshmallow base_fields.Function

base_fields.Nested中的Flask-marshmallow base_fields.Function
EN

Stack Overflow用户
提问于 2018-07-10 12:47:24
回答 1查看 890关注 0票数 2

我在使用marshmallow-sqlalchemyflask-marshmallow

我希望有我自己的HATEOAS实现:对于n对多关系,以及链接,我希望有对象的计数。

为此,我有一个具有多对多关系的常规sqlalchemy模型:

代码语言:javascript
复制
class ParentChild(Model):
    __tablename__ = 'parrent_child'
    parent_id =Column(Integer, ForeignKey('parent.id'), primary_key=True)
    child_id = Column(Integer, ForeignKey('child.id'), primary_key=True)

class Parent(Model):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    name = Column(String())
    children = relationship('Child', secondary='parent_child', back_populates='parents')

class Child(Model):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    name = Column(String())
    parents = relationship('Parent', secondary='parent_child', back_populates='children')

使用下面的marshmallow模式,我设法获得了我想要的数据:

代码语言:javascript
复制
class ParentSchema(Schema):
    class Meta:
        model = Parent
    children = URLFor('api.parents_children_by_parent_id', parent_id='<id>')
    children_count = base_fields.Function(lambda obj: len(obj.children))

返回:

代码语言:javascript
复制
{
    "id" : 42,
    "name" : "Bob",
    "children" : "/api/parents/42/children",
    "children_count" : 3
}

但是当我想像这样封装这些字段时,我会遇到一些问题:

代码语言:javascript
复制
{
     "id": 42
     "name": "bob",
     "children": {
         "link": "/api/parents/42/children",
         "count": 3
     }
}

我试着用base_fields.Dict

代码语言:javascript
复制
children = base_fields.Dict(
    link = URLFor('api.parents_children_by_parent_id', parent_id='<id>'),
    count = base_fields.Function(lambda obj: len(obj.children))
) 

但我得到了TypeError: Object of type 'Child' is not JSON serializable

我尝试了其他各种解决方案,但都没有成功:flask-marshmallow的Hyperlinks只接受超链接字典,而不接受函数。

我认为解决方案是使用base_fields.Nested,但它打破了URLFor无法捕获'<id>'的行为。我在文档中找不到这个问题的解决方案。

在某种程度上,很难跳出框框来思考。我是不是遗漏了什么?任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

发布于 2018-07-10 15:43:06

所以我找到了一个解决办法,我打算把它贴出来,但我认为它还可以改进。

为了用我想要的对象覆盖children字段,我使用了一个base_fields.Method

代码语言:javascript
复制
class ParentSchema(Schema):
    class Meta:
        model = Parent

    children = base_fields.Method('build_children_obj')

    def build_children_obj(self, obj):
        return {
            "count": len(obj.children),
            "link": URLFor('api.parents_children_by_parent_id', parent_id=obj.id)
        }

在这一点上,我得到了TypeError: Object of type 'URLFor' is not JSON serializable

因此,在检查了URLFor_serialize方法的源代码之后,我在我的(自定义)JSONEncoder中添加了一个检查:

代码语言:javascript
复制
if isinstance(o, URLFor):
    return str(o._serialize(None, None, o))

我终于得到了我想要的有效载荷,但我发现它并不是很干净。有什么想法吗?

编辑:经过测试,我发现通过加载整个子列表来获取计数的len(obj.children)非常耗费资源。取而代之的是,我使用db.session.query(func.count(Children.id)).filter(Children.parents.any(id=obj.id)).scalar(),它是更优化的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51257431

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档