【问题标题】:python sqlalchemy orm one to many bidirectional relation - mapping a json to multiple tablespython sqlalchemy orm 一对多双向关系 - 将json映射到多个表
【发布时间】:2020-10-14 21:19:29
【问题描述】:

我正在使用 sqlalchemy orm 将 json 映射到多个表。 我有两张桌子,每张桌子都有一个班级。

其中一个表有一个参数,它是一个字典列表,必须映射到第二个表的不同列。


from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class A(Base):
    __tablename__ = 'a'
    id = Column(primary_key, Interger(10))
    param1 = Column(String(45))
    param2 = Column(String(45))
    atobmap = relationship('B', lazy='subquery', back_populates="a")

class B(Base):
    __tablename__ = 'b'
    bid = Column(primary_key=True, nullable=True, Integer(15))
    bparam1 = Column(ForeignKey('a.id'), nullable=False)
    bparam2 = Column(String(45))
    a = relationship('A', back_populates='b')

示例 json:

{
    "id": 1,
    "param1": "Value",
    "param2": "Value",
    "atobmap": [
                 { "bid": 1,
                   "bparam1": 1,
                   "bparam2": "Value"
                 },
                 { "bid": 2,
                   "bparam1": 1,
                   "bparam2": "Value"
                 }
               ]
}

当我手动将数据插入表并执行 GET 时,它工作正常并且按预期返回值,尽管它在我的 atobmap 字典中添加了一个带有 value {} 的 _sa_instance_state 键。

{
...
"atobmap": [
                 { "_sa_instance_state": {}
                   "bid": 1,
                   "bparam1": 1,
                   "bparam2": "Value"
                 },
                 { "_sa_instance_state": {}
                   "bid": 2,
                   "bparam1": 1,
                   "bparam2": "Value"
                 }
       ]
}            

但是当我尝试发布这些值时,它会抛出一个 错误 说 "Unhashable type: dict".

【问题讨论】:

  • 您应该添加更多实际执行插入的代码或引发错误的行

标签: python sqlalchemy


【解决方案1】:

您可以使用类似于下面的函数。

它需要一个 SQLAlchemy 模型和一个字段/值对字典和 返回一个模型实例。忽略字典中的键 不是模型上的字段。遍历和实例化关系。

例子:

我们的模型包括一个公司模型,其名称字段是一个字符串 和一个用户字段,它与用户模型是一对多的关系。

我们的数据如下所示。

{ “公司”: { “名称”:“奥沃加” “用户”:[ { “名称”:“埃里克” } ] } }

我们将使用 SQLAlchemy 的 class_mapper 函数来获取“映射器” 为模型。然后我们可以访问mapper.attrs.keys() 获取列表 所有映射的字段。任何不是关系的键,简单地说 将它们从数据中提取出来。对于关系的键,获取映射器 关系,然后使用该相关映射器递归调用from_json 和子数据。然后,将该新实例附加到父实例。

def from_json(model, data):
    mapper = class_mapper(model)
    keys = mapper.attrs.keys()
    relationships = inspect(mapper).relationships
    args = {k: v for k, v in data.items() if k in keys and k not in relationships}
    instance = model(**args)
    for attr, relationship in relationships.items():
        if relationship.direction in [MANYTOMANY, ONETOMANY]:
            relationship_instances = [
                from_json(relationship.mapper.class_, el) for el in data[attr]
            ]
            setattr(instance, attr, relationship_instances)
        elif relationship.direction == MANYTOONE:
            try:
                relationship_instance = from_json(
                    relationship.mapper.class_, data[attr]
                )
            except KeyError:
                pass
            else:
                setattr(instance, attr, relationship_instance)
    return instance

【讨论】:

    猜你喜欢
    • 2021-06-26
    • 1970-01-01
    • 2019-04-07
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 2016-08-07
    • 2020-09-18
    • 1970-01-01
    相关资源
    最近更新 更多