python - python sqlalchemy orm 一对多双向关系 - 将json映射到多个表
问题描述
我正在使用 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".
解决方案
您可以使用类似于下面的功能。
它接受一个 SQLAlchemy 模型和一个字段/值对字典并返回一个模型实例。忽略字典中不是模型字段的键。遍历和实例化关系。
例子:
我们的模型包括一个 Company 模型,其 name 字段是字符串,users 字段是与 User 模型的一对多关系。
我们的数据如下所示。
{“公司”:{“名称”:“Owoga”“用户”:[{“名称”:“埃里克”}]}}
我们将使用 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
推荐阅读
- angular - Ionic4 - 除了以下示例和文档之外,PhotoViewer 无法正常工作。图像不显示
- java - 如何在 cmd/sudo 中输入 args 并在运行时使用它们?(爪哇)
- http-error - 尝试在 centos 8 上访问 localhost/phpmyadmin 时出现 HTTP 错误 500
- javascript - Puppeteer node_modules TypeError:无法解构'module.exports'的属性'formatters',因为它未定义
- javascript - Mapbox 地理编码 API - “跨源请求被阻止”错误
- node.js - 无论如何在Nodejs中使用multer(multer s3)解压缩文件数组并将其上传到AWS S3
- emacs - Emacs 26.3:在删除词、按词移动等时改变“一个词”的定义
- python - 在 Pandas 中使用二级索引值将列转换为行
- sql - 按升序对 varchar 列进行数字排序
- java - java.sql.SQLException:列“名称”的值超出范围:值 Finn