当前位置: 首页 > 面试题库 >

如何通过带有联接的数据库查询生成嵌套的JSON?使用Python / SQLAlchemy

章建木
2023-03-14
问题内容

我有一个指定的用例,但我的问题通常与执行此操作的最佳方法有关。

我有三张桌子

订单-主键order_id

OrderLine- 具有order_id,product_id和数量的 链接表 。一个订单有1个或更多订单行

产品-主键product_id,每个订单行都有一个产品

在sqlachemy / python中,如何按照以下方式生成嵌套的JSON:

{
    "orders": [
        {
            "order_id": 1
            "some_order_level_detail": "Kansas"
            "order_lines": [
                {
                    "product_id": 1,
                    "product_name": "Clawhammer",
                    "quantity": 5
                },
                ...
            ]
        },
        ...
    ]
}

潜在想法

摆脱做连续的查询

如果可能的话,我想摆脱的第一个想法是使用列表混合和蛮力方法。

def get_json():
    answer = {
        "orders": [
            {
                "order_id": o.order_id,
                "some_order_level_detail": o.some_order_level_detail,
                "order_lines": [
                    {
                        "product_id": 1,
                        "product_name": Product.query.get(o_line.product_id).product_name,
                        "quantity": 5
                    }
                    for o_line in OrderLine.query.filter(order_id=o.order_id).all()
                ]
            }
            for o in Order.query.all()
        ]
    }

这很难维持将查询与json混合在一起。理想情况下,我想先进行查询…

首先获得合并结果,然后以某种方式进行操作

第二个想法是执行联接查询,以联接OrderLine订单和产品详细信息中每行显示的三个表。

我对pythonista的问题是有一种将其转换为嵌套json的好方法。

其他方式?

这真的看起来像是一个常见的要求,我真的想知道对于这种事情是否有预定方法?是否有一个SQLAchemy版本本


问题答案:

研究一下marshmallow-sqlalchemy,它确实可以满足您的需求。

我强烈建议您不要将序列化直接烘焙到模型中,因为您最终将有两个服务请求相同的数据,但是以不同的方式进行序列化(例如,包括更少或更多的嵌套关系以提高性能),您要么最终选择要么(1)测试套件会遗漏许多错误,除非您要逐字检查每个字段,或者(2)序列化的数据量超过所需数量,并且随着应用程序的复杂性扩展,您将遇到性能问题。

使用marshmallow-sqlalchemy,您需要为要序列化的每个模型定义一个架构。是的,这有点多余,但是请相信我-最终您会更加快乐。

我们像这样使用flask-sqlalchemy和marshmallow-
sqlalchemy构建应用程序(也强烈建议使用factory_boy,以便您可以模拟服务并编写单元测试来代替需要接触数据库的集成测试):

# models

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child", back_populates="parent")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))
    parent = relationship('Parent', back_populates='children',
                          foreign_keys=[parent_id])

# schemas. Don't put these in your models. Avoid tight coupling here

from marshmallow_sqlalchemy import ModelSchema
import marshmallow as ma


class ParentSchema(ModelSchema):
    children = ma.fields.Nested(
        'myapp.schemas.child.Child', exclude=('parent',), many=True)
    class Meta(ModelSchema.Meta):
        model = Parent
        strict = True
        dump_only = ('id',)


class ChildSchema(ModelSchema):
    parent = ma.fields.Nested(
        'myapp.schemas.parent.Parent', exclude=('children',))
    class Meta(ModelSchema.Meta):
        model = Child
        strict = True
        dump_only = ('id',)

# services

class ParentService:
    '''
    This service intended for use exclusively by /api/parent
    '''
    def __init__(self, params, _session=None):
        # your unit tests can pass in _session=MagicMock()
        self.session = _session or db.session
        self.params = params

    def _parents(self) -> typing.List[Parent]:
        return self.session.query(Parent).options(
            joinedload(Parent.children)
        ).all()

    def get(self):
        schema = ParentSchema(only=(
            # highly recommend specifying every field explicitly
            # rather than implicit
            'id',
            'children.id',
        ))
        return schema.dump(self._parents()).data

# views

@app.route('/api/parent')
def get_parents():
    service = ParentService(params=request.get_json())
    return jsonify(data=service.get())


# test factories
class ModelFactory(SQLAlchemyModelFactory):
    class Meta:
        abstract = True
        sqlalchemy_session = db.session

class ParentFactory(ModelFactory):
    id = factory.Sequence(lambda n: n + 1)
    children = factory.SubFactory('tests.factory.children.ChildFactory')

class ChildFactory(ModelFactory):
    id = factory.Sequence(lambda n: n + 1)
    parent = factory.SubFactory('tests.factory.parent.ParentFactory')

# tests
from unittest.mock import MagicMock, patch

def test_can_serialize_parents():
    parents = ParentFactory.build_batch(4)
    session = MagicMock()
    service = ParentService(params={}, _session=session)
    assert service.session is session
    with patch.object(service, '_parents') as _parents:
        _parents.return_value = parents
        assert service.get()[0]['id'] == parents[0].id
        assert service.get()[1]['id'] == parents[1].id
        assert service.get()[2]['id'] == parents[2].id
        assert service.get()[3]['id'] == parents[3].id


 类似资料:
  • 我在使用FOQElasticaBundle构建查询时遇到问题 我有3个实体 null

  • 问题内容: 这是我在elasticsearch中存储在索引上的数据类型。我必须找到包含主要成分牛肉(且重量小于1000)和成分-(辣椒粉且重量小于250),(橄榄油和重量小于300)以及所有其他成分类似的食谱。 索引的映射是 我的查询是 但这给了Null。有人可以帮我吗?我认为我没有正确使用嵌套查询 问题答案: 试试这个:

  • 问题内容: 我正在尝试使用PostgreSQL 9.2中添加的功能将查询结果映射到JSON 。 我在找出将连接的行表示为嵌套对象(1:1关系)的最佳方式时遇到麻烦 这是我尝试过的内容(设置代码:表格,示例数据,后跟查询): 查询本身: 我发现如果使用,我可以将结果字段分离为一个子对象,但似乎仅限于一个级别。我不能插入更多的语句,因为我认为在这种情况下我需要。 为我提供了列名,因为在该表的结果中,我

  • 问题内容: 我试图在MySQL 5.7.12版(本手册的13.16节)中仅使用本机JSON功能(无PHP等),我试图编写一个查询以从包含子对象的关系表中生成JSON文档。给出以下示例: 我正在尝试生成如下所示的JSON文档: 我是MySQL的新手,并且怀疑有一种SQL模式可以从一对多关系生成嵌套的JSON对象,但是我很难找到它。 在Microsoft SQL(我更熟悉)中,它的工作原理如下: 我试

  • 我有一个带有嵌套映射的索引。我想预先形成一个查询,该查询将返回以下内容:给我搜索词中每个单词出现在一个或多个嵌套文档中的所有文档。 以下是索引: 以下是我尝试的最新查询: 例如,如果我搜索单词“食物和水”,我希望每个单词至少出现在嵌套文档中。即使只有一个单词存在,当前搜索也会返回文档 谢谢你的帮助! 更新:正如克里斯托所建议的,解决方案有效。现在我有以下问题。 这是我的索引: 我要执行的查询是,如

  • 我正在努力编写一个具有多个和/或条件的弹性搜索查询。 它的基本逻辑如下: 正如docs中提到的,如果一个文档只满足must子句,那么它就被认为是匹配的。在这种情况下,should子句起到增强作用,即如果文档除了mouth子句之外还匹配一个或多个should子句,那么它将具有更高的相关性得分,假设cond2、cond3和cond4是计算相关性得分的查询。 问题是我只想要至少匹配OR条件之一的文档。