将关联对象与 back_populates 一起使用时,SQLAlchemy 抛出 KeyError – 文档中的示例不起作用

2023-12-05

SQLAlchemy 很好的文档如何使用关联对象back_populates.

但是,当从该文档复制并粘贴示例时,将子项添加到父项会引发KeyError如下面的代码所示。模型类 100% 从文档中复制:

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

Base = declarative_base(metadata=MetaData())

class Association(Base):
    __tablename__ = 'association'
    left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
    right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
    extra_data = Column(String(50))
    child = relationship("Child", back_populates="parents")
    parent = relationship("Parent", back_populates="children")

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

class Child(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)
    parents = relationship("Association", back_populates="child")

parent = Parent(children=[Child()])

使用 SQLAlchemy 版本 1.2.11 运行该代码会引发以下异常:

lars$ venv/bin/python test.py
Traceback (most recent call last):
  File "test.py", line 26, in <module>
    parent = Parent(children=[Child()])
  File "<string>", line 4, in __init__
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 417, in _initialize_instance
    manager.dispatch.init_failure(self, args, kwargs)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 66, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 249, in reraise
    raise value
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 414, in _initialize_instance
    return manager.original_init(*mixed[1:], **kwargs)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/ext/declarative/base.py", line 737, in _declarative_constructor
    setattr(self, k, kwargs[k])
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 229, in __set__
    instance_dict(instance), value, None)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 1077, in set
    initiator=evt)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/collections.py", line 762, in bulk_replace
    appender(member, _sa_initiator=initiator)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/collections.py", line 1044, in append
    item = __set(self, item, _sa_initiator)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/collections.py", line 1016, in __set
    item = executor.fire_append_event(item, _sa_initiator)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/collections.py", line 680, in fire_append_event
    item, initiator)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 943, in fire_append_event
    state, value, initiator or self._append_token)
  File "/Users/lars/coding/sqlalchemy_association_object_test/venv/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 1210, in emit_backref_from_collection_append_event
    child_impl = child_state.manager[key].impl
KeyError: 'parent'

我已将其归档为SQLAlchemy 问题跟踪器中的错误。也许有人可以同时向我指出一个可行的解决方案或解决方法?


tldr;我们必须使用关联代理扩展and为关联对象创建一个自定义构造函数,它将子对象作为第一个 (!) 参数。请参阅基于以下问题示例的解决方案。

SQLAlchemy 的文档实际上在下一段中指出,如果我们想直接添加,我们还没有完成Child模型到Parent跳过中介的模型Association models:

以直接形式使用关联模式需要: 子对象在被关联之前先与关联实例关联 附加到父级;同样,从父母到孩子的访问 通过关联对象。

# create parent, append a child via association
p = Parent()
a = Association(extra_data="some data")
a.child = Child()
p.children.append(a)

编写问题中所要求的方便的代码,即p.children = [Child()],我们必须利用关联代理扩展.

这是使用关联代理扩展的解决方案,它允许“直接”将子级添加到父级,而无需在它们之间显式创建关联:

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import backref, relationship
from sqlalchemy.schema import MetaData

Base = declarative_base(metadata=MetaData())

class Association(Base):
    __tablename__ = 'association'
    left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
    right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
    extra_data = Column(String(50))
    child = relationship("Child", back_populates="parents")
    parent = relationship("Parent", backref=backref("parent_children"))

    def __init__(self, child=None, parent=None):
        self.parent = parent
        self.child = child

class Parent(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    children = association_proxy("parent_children", "child")

class Child(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)
    parents = relationship("Association", back_populates="child")

p = Parent(children=[Child()])

不幸的是我只知道如何使用backref代替back_populates这不是“现代”方法。

特别注意创建自定义__init__以孩子为对象的方法first争论。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将关联对象与 back_populates 一起使用时,SQLAlchemy 抛出 KeyError – 文档中的示例不起作用 的相关文章

  • 当参数为 0 与任何其他整数时,如何为返回不同类型的函数创建重载注释?

    是否可以为当参数为时返回不同类型的函数创建重载注释0与任何其他整数 def foo val int gt MyObjectA MyObjectB if val 0 return MyObjectA return MyObjectB 有没有办
  • 如何将 Jupyter Notebook 的代码片段与 VSCode 结合使用?

    我已经使用 VSCode 一段时间了 目前我正在尝试设置代码片段来工作 它们似乎适用于简单的 Python py 文件 但不适用于 Jupyter Notebook ipynb 文件 有什么办法可以让他们一起工作吗 片段就在这里 Creat
  • Matplotlib imshow:如何在矩阵上应用蒙版

    我正在尝试以图形方式分析二维数据 matplotlib imshow在这方面非常有用 但我觉得如果我可以从矩阵中排除一些单元格 超出感兴趣范围的值 我可以更多地利用它 我的问题是这些值使我感兴趣的范围内的色彩图 变平 排除这些值后 我可以获
  • 向下投射通用元素类型

    public class ConfigControlBase
  • Python 中的自然日/相对日

    我想要一种在 Python 中显示日期项目的自然时间的方法 类似于 Twitter 将显示 刚才 几分钟前 两小时前 三天前 等消息 Django 1 0 在 django contrib 中有一个 人性化 方法 我没有使用 Django
  • 使用Python选择屏幕区域

    我正在用 Python 开发一个屏幕截图实用程序 目前它是专门针对 Linux 的 到目前为止 我已经能够拍摄完整桌面的屏幕截图 并将其上传到 Imgur 然后将链接复制到剪贴板 现在我想扩展到诸如活动窗口或特定选择的屏幕截图之类的功能 如
  • 会话cookie太大烧瓶应用程序[重复]

    这个问题在这里已经有答案了 我正在尝试使用会话 本地 加载某些数据 并且它已经工作了一段时间 但是现在我收到以下警告 并且不再加载通过会话加载的数据 b session cookie 太大 该值是 13083 字节 但是 标头需要 44 个
  • 如何获取一个类的所有实例

    我是一名初学者 正在学习 Python 我想创建一个课程Person 在构造函数中 我想将我创建的每个实例放入一个名为 实例 的集合中 然后我希望实例 方法返回所有实例 我怎样才能做到这一点 class Person Type annota
  • 在 Flask 中将配置文件作为字典读取

    在 instance app cfg 我已经配置 test test 在我的烧瓶文件 app py 中 with app open instance resource app cfg as f config f read print con
  • python下安装xgboost 32位msys失败

    尝试安装 xgboost 失败 Windows 和企业版版本为 Anaconda 2 1 0 64 位 我该如何继续 我一直在使用 R 似乎从 RStudio 在 R 中安装新包相当容易 但在间谍程序中则不然 因为我需要进入命令窗口来执行此
  • While 在范围内循环用户输入

    我有一些代码 我想要求用户输入 1 100 之间的数字 如果他们在这些数字之间输入一个数字 它将打印 Size input 并打破循环 但是 如果他们在外部输入一个数字1 100 它将打印 大小 输入 并继续向他们重新询问一个数字 但我遇到
  • 将多个 csv 文件连接成具有相同标头的单个 csv

    我目前正在使用以下代码导入 6 000 个 csv 文件 带标题 并将它们导出到单个 csv 文件 带单个标题行 import csv files from folder path r data US market merged data
  • 调度算法,找到设定长度的所有非重叠区间

    我需要为我的管理应用程序实现一种算法 该算法将告诉我何时可以将任务分配给哪个用户 我实现了一个蛮力解决方案 它似乎有效 但我想知道是否有更有效的方法来做到这一点 为了简单起见 我重写了算法以对数字列表进行操作 而不是数据库查询等 下面我将尝
  • python 从字典中获取唯一值

    我想从我的字典中获取唯一的值 Input 320 167 316 0 319 167 401 167 319 168 380 167 265 166 期望的输出 167 0 168 166 我的代码 unique values sorted
  • .NET 是否有相当于 Python 中的 **kwargs 的功能?

    我一直无法通过典型渠道找到这个问题的答案 在Python中我可以有以下函数定义 def do the needful kwargs Kwargs is now a dictionary i e do the needful spam 42
  • Keras CNN 回归模型损失低,准确度为 0

    我在 keras 中遇到这个 NN 回归模型的问题 我正在研究一个汽车数据集 以根据 13 个维度预测价格 简而言之 我已将其读取为 pandas 数据帧 将数值转换为浮点数 缩放值 然后对分类值使用 one hot 编码 这创建了很多新列
  • Mxnet - 缓慢的数组复制到 GPU

    我的问题 我应该如何在 mxnet 中执行快速矩阵乘法 我的具体问题 数组复制到 GPU 的速度很慢 对此我们能做些什么呢 我创建随机数组 将它们复制到上下文中 然后相乘 import mxnet as mx import mxnet nd
  • Django model.foreignKey 并返回 self.text 错误

    所以我正在 Django 中处理 model py 但遇到了 2 个 pylint 错误 我不明白为什么 这是 pylint 的问题还是我在代码中做错了什么 E1120 No value for argument on delete in
  • 通过 Selenium 和 python 切换到 iframe

    我如何在硒中切换到这个 iframe 只知道 您可以使用 XPath 来定位 iframe driver find element by xpath iframe name Dialogue Window Then switch to th
  • 如何将 pygame Surface 转换为 PIL 图像?

    我正在使用 PIL 来透视地变换屏幕的一部分 原始图像数据是一个 pygame Surface 需要转换为 PIL 图像 因此我发现了 pygame 的 tostring 函数就是为了这个目的而存在的 然而结果看起来很奇怪 见附图 这段代码

随机推荐