SQLAlchemy ORM 无法使用复合外键

2023-12-01

我正在尝试使用几个相关模型构建一个示例,如下所示。 我们有一个模型 B 与模型 C 具有 1:n 关系;那么我们就有一个模型 A,与 B 之间存在 n:1 关系,与 C 之间存在 n:1 关系。(C 有 2 列主键)

我尝试了这段代码:

class C(db.Model):
    __tablename__ = 'C'
    key1 = Column(Integer, primary_key=True)
    key2 = Column(Integer, primary_key=True)
    attr1 = Column(Date)
    attr2 = Column(Boolean)
    related_b = Column(Integer, ForeignKey('B.spam'))


class B(db.Model):
    __tablename__ = 'B'
    spam = Column(Integer, default=1, primary_key=True)
    eggs = Column(String, default='eggs')
    null = Column(String)
    n_relation = relationship(C, foreign_keys='C.related_b')


class A(db.Model):
    __tablename__ = 'A'
    foo = Column(String, default='foo', primary_key=True)
    bar = Column(String, default='bar', primary_key=True)
    baz = Column(String, default='baz')
    rel = relationship(B, foreign_keys='A.related_b')
    related_b = Column(Integer, ForeignKey('B.spam'))
    related_c1 = Column(Integer, ForeignKey('C.key1'))
    related_c2 = Column(Integer, ForeignKey('C.key2'))
    other_rel = relationship(C, foreign_keys=(related_c1, related_c2))

只是为了得到例外:

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship A.other_rel - there are multiple foreign key paths linking the tables.  Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

但是嘿,我已经通过了这个论点。 我尝试了该参数的各种版本,通过名称指定 A 列,通过名称指定 C 列,通过直接引用指定 C 列,似乎没有什么会影响此错误。 我还尝试使用单个复合外键,如下所示:

class A(db.Model):
    __tablename__ = 'A'
    foo = Column(String, default='foo', primary_key=True)
    bar = Column(String, default='bar', primary_key=True)
    baz = Column(String, default='baz')
    rel = relationship(B, foreign_keys='A.related_b')
    related_b = Column(Integer, ForeignKey('B.spam'))
    related_c1 = Column(Integer, ForeignKey('C.key1'))
    related_c2 = Column(Integer, ForeignKey('C.key2'))
    compound = ForeignKeyConstraint(('related_c1', 'related_c2'), ('C.key1', 'C.key2'))
    other_rel = relationship(C, foreign_keys=compound)

但一切都没有改变。 我是否弄错了什么或者这是一个错误? (至少,错误消息不正确......)


这里的问题是你必须声明ForeignKeyConstraint() in __table_args__,不在类的主体中。

换句话说,以下代码不会将外键约束应用于子表......

from sqlalchemy import create_engine, Column, Integer, text, ForeignKeyConstraint, String
from sqlalchemy.orm import declarative_base, relationship

connection_url = r"mssql+pyodbc://@.\SQLEXPRESS/myDb?driver=ODBC+Driver+17+for+SQL+Server"
engine = create_engine(connection_url)
Base = declarative_base()


class Parent(Base):
    __tablename__ = "tbl_parent"
    id1 = Column(Integer, primary_key=True)
    id2 = Column(Integer, primary_key=True)
    parent_name = Column(String(50))
    children = relationship("Child", back_populates="parent")


class Child(Base):
    __tablename__ = "tbl_child"
    id = Column(Integer, primary_key=True, autoincrement=False)
    child_name = Column(String(50))
    parent_id1 = Column(Integer)
    parent_id2 = Column(Integer)
    # this does not work
    ForeignKeyConstraint(
        ["parent_id1", "parent_id2"], ["tbl_parent.id1", "tbl_parent.id2"]
    )
    parent = relationship(
        "Parent",
        foreign_keys="[Child.parent_id1, Child.parent_id2]",
        back_populates="children",
    )


Base.metadata.drop_all(engine)
engine.echo = True
Base.metadata.create_all(engine)

"""DDL emitted:
CREATE TABLE tbl_parent (
    id1 INTEGER NOT NULL, 
    id2 INTEGER NOT NULL, 
    parent_name VARCHAR(50), 
    PRIMARY KEY (id1, id2)
)
CREATE TABLE tbl_child (
    id INTEGER NOT NULL, 
    child_name VARCHAR(50), 
    parent_id1 INTEGER, 
    parent_id2 INTEGER, 
    PRIMARY KEY (id)
)
"""

… 但是这个will work …

from sqlalchemy import create_engine, Column, Integer, text, ForeignKeyConstraint, String
from sqlalchemy.orm import declarative_base, relationship

connection_url = r"mssql+pyodbc://@.\SQLEXPRESS/myDb?driver=ODBC+Driver+17+for+SQL+Server"
engine = create_engine(connection_url)
Base = declarative_base()


class Parent(Base):
    __tablename__ = "tbl_parent"
    id1 = Column(Integer, primary_key=True)
    id2 = Column(Integer, primary_key=True)
    parent_name = Column(String(50))
    children = relationship("Child", back_populates="parent")


class Child(Base):
    __tablename__ = "tbl_child"
    # this works
    __table_args__ = (
        ForeignKeyConstraint(
            ["parent_id1", "parent_id2"], ["tbl_parent.id1", "tbl_parent.id2"]
        ),
    )
    id = Column(Integer, primary_key=True, autoincrement=False)
    child_name = Column(String(50))
    parent_id1 = Column(Integer)
    parent_id2 = Column(Integer)

    parent = relationship(
        "Parent",
        foreign_keys="[Child.parent_id1, Child.parent_id2]",
        back_populates="children",
    )


Base.metadata.drop_all(engine)
engine.echo = True
Base.metadata.create_all(engine)

"""DDL emitted:
CREATE TABLE tbl_parent (
    id1 INTEGER NOT NULL, 
    id2 INTEGER NOT NULL, 
    parent_name VARCHAR(50) NULL, 
    PRIMARY KEY (id1, id2)
)
CREATE TABLE tbl_child (
    id INTEGER NOT NULL, 
    child_name VARCHAR(50) NULL, 
    parent_id1 INTEGER NULL, 
    parent_id2 INTEGER NULL, 
    PRIMARY KEY (id), 
    FOREIGN KEY(parent_id1, parent_id2) REFERENCES tbl_parent (id1, id2)
)
"""

参考:

https://docs.sqlalchemy.org/en/14/orm/declarative_tables.html#orm-declarative-table-configuration

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

SQLAlchemy ORM 无法使用复合外键 的相关文章

  • 如何使用 cython 编译扩展?

    我正在尝试从示例页面编译一个简单的 cython 扩展here http docs cython org src userguide tutorial html在我安装了 Python 2 6 64 位版本的 Windows 7 64 位计
  • 在 Pandas 中按日期获取有效合约

    我在检测 pandas DataFrame 中的活动合约方面遇到了一些困难 假设每一行都是一个协商 对于每一行 我有两列 initial date 和 end date 我想知道的是按日期划分的活跃合约数量 到目前为止我做了一个非常低效的方
  • Python BeautifulSoup XML 解析

    我编写了一个简单的脚本来使用 BeautifulSoup 模块解析 XML 聊天日志 标准 soup prettify 工作正常 只是聊天日志中有很多绒毛 您可以在下面看到我正在使用的脚本代码和一些 XML 输入文件 Code import
  • 可以在 TensorFlow 中使用排名相关作为成本函数吗?

    我正在处理偶尔充满异常值的极其嘈杂的数据 因此我主要依靠相关性来衡量我的神经网络的准确性 是否可以明确使用诸如等级相关性 斯皮尔曼相关系数 之类的东西作为我的成本函数 到目前为止 我主要依赖 MSE 作为相关性的代理 我现在面临三个主要障碍
  • 错误:permission_manager_qt.cpp(82) 不支持的权限类型:13

    我正在开发具有内置浏览器功能的 python 代码 PyQt 5 13 import sys from PyQt5 QtCore import from PyQt5 QtGui import from PyQt5 QtWidgets imp
  • 如何从 Dockerfile 安装 Python 3.7 和 Pip

    我正在尝试构建基于 Ubuntu 18 04 的自定义 Docker 映像 Ubuntu 预装了 Python 3 6 但我想 1 安装 Python 3 7 2 将其设置为默认 Python 版本 这样就可以使用python代替pytho
  • Python igraph:从图中删除顶点

    我正在使用安然电子邮件数据集 并尝试删除没有 enron com 的电子邮件地址 即我只想拥有安然电子邮件 当我尝试删除那些没有 enron com 的地址时 一些电子邮件由于某些原因被跳过 下面显示了一个小图 其中顶点是电子邮件地址 这是
  • sudo pip install python-Levenshtein 失败,错误代码 1

    我正在尝试在 Linux 上安装 python Levenshtein 库 但每当我尝试通过以下方式安装它时 sudo pip install python Levenshtein 我收到此错误 命令 usr bin python c 导入
  • 如何通过双击在浏览器中打开 ipynb 文件

    以前 我安装了 Canopy 当时 我只需双击 ipynb 文件并在浏览器中打开它们即可 但是 后来我需要Anaconda 一旦我安装了它 这个功能就没有了 现在我只希望能够简单地双击 ipynb 文件 然后该文件就会在 Firefox 中
  • 更改 pandas 中多个日期时间列的时区信息

    有没有一种简单的方法可以将数据帧中的所有时间戳列转换为本地 任何时区 不是逐列进行吗 您可以有选择地将转换应用于所有日期时间列 首先 选择它们select dtypes https pandas pydata org pandas docs
  • 具有多个元素的数组的真值是二义性错误吗? Python

    from numpy import from pylab import from math import def TentMap a x if x gt 0 and x lt 0 5 return 2 a x elif x gt 0 5 a
  • 如何使用Python的super()来更新父值?

    我对继承很陌生 之前所有关于继承和 Python 的 super 函数的讨论都有点超出我的理解 我当前使用以下代码来更新父对象的值 usr bin env python test py class Master object mydata
  • 外键引用多个表

    我有4张桌子 A ida name B ida B specific stuff C ida C specific stuff D ida D specific stuff 我希望另一个表 E 可以仅引用 B 或 C 而不是 D 我可以在其
  • Python - 如何查询定义方法的类?

    我的问题有点类似于this one https stackoverflow com questions 5520580 how do you get all classes defined in a module but not impor
  • Python组合目录中的所有csv文件并按日期时间排序

    我有 2 年的每日数据分成每月文件 我想将所有这些数据合并到一个按日期和时间排序的文件中 我正在使用的代码组合了所有文件 但不按顺序 我正在使用的代码 import pandas as pd import glob os import cs
  • 如何将列表字典写入字符串而不是 CSV 文件?

    This 堆栈溢出问题 https stackoverflow com questions 37997085 how to write a dictionary of lists to a csv file将列表字典写入 CSV 文件的答案
  • 异步和协程与任务队列

    我一直在阅读有关 python 3 中的 asyncio 模块的内容 以及更广泛地了解 python 中的协程的内容 但我不明白是什么让 asyncio 成为如此出色的工具 我的感觉是 你可以用协程做的所有事情 通过使用基于多处理模块 例如
  • 在 Python 模块中使用 InstaLoader

    我正在尝试使用 Instaloader 下载与主题标签相关的照片以进行图像分析 我在GitHub存储库中找到了一个全面的方法 如何在终端中执行它 但是 我需要将脚本集成到Python笔记本中 这是脚本 instaloader no vide
  • 来自 django 教程 was_published_recently.admin_order_field = 'pub_date'

    From Django 教程 https www jetbrains com help pycharm 2017 1 creating and running your first django project html d28041e21
  • Django South - 将 null=True 字段转换为 null=False 字段

    我的问题是 转变的最佳做法是什么null True场变成null False使用 Django South 的字段 具体来说 我正在与ForeignKey 你应该先写一个数据迁移 http south aeracode org docs t

随机推荐