sqlalchemy中带有反射和声明性语法的一对多关系定义给出了连接条件

2024-10-01 17:33:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在现有数据库上设置一对多关系。在

简化的DDL为:

create table accnt (
  code varchar(20) not null
  , def varchar(100)
  , constraint pk_accnt primary key (code)
);

commit;

create table slorder (
  code varchar(20) not null
  , def varchar(100)
  , dt date
  , c_accnt varchar(20) not null
  , constraint pk_slorder primary key (code)
  , constraint fk_slorder_accnt foreign key (c_accnt)
     references accnt (code)
     on update cascade on delete cascade
);

commit;

SqlAlchemy代码:

^{pr2}$

给予

sqlalchemy.exc.ArgumentError: Could not determine join condition between parent/child tables on relationship SlOrder.accnt.  Specify a 'primaryjoin' expression.  If 'secondary' is present, 'secondaryjoin' is needed as well.

错误。在

我对这个问题的可能解决办法是:

1

class SlOrder(Base):
    __tablename__ = 'slorder'
    __table_args__ = {'autoload': True}

    defi = Column("def", String(100))
    c_accnt = Column("c_accnt", String(20), ForeignKey('accnt.code'))

    accnt = relationship('Accnt', backref='slorders')

但是这种方法需要我手动添加每一个外键约束列,这将导致反射可用。(因为我有很多列引用了其他表。)

2

class SlOrder(Base):
    __table__ = Table('accnt', metadata, autoload = True, autoload_with=engine)
    accnt = relationship('Accnt', backref='slorders', primaryjoin=(__table__.c_accnt==Accnt.code))

这种方法还有另一个后果(请参见my previous question

那我还缺什么呢?使用反射和声明性语法定义关系的最佳方法是什么?在

编辑:

我认为,如果子表只有一个对父表的引用,SqlAlchemy会查找并构建关系。在

但如果子表有多个引用,则为:

create table slorder (
  code varchar(20) not null
  , def varchar(100)
  , dt date
  , c_accnt varchar(20) not null
  , c_accnt_ref  varchar(20) 
  , constraint pk_slorder primary key (code)
  , constraint fk_slorder_accnt foreign key (c_accnt)
     references accnt (code)
     on update cascade on delete cascade

  , constraint fk_slorder_accnt_ref foreign key (c_accnt_ref)
     references accnt (code)
     on update cascade on delete no action
);

出现上述错误。在

那么,如果两个表之间存在多个关系,SqlAlchemy的预期行为是否会出错?在


Tags: key关系ondefcreatetablenotcode
2条回答

我认为您必须在子表中添加ForeignKey。在

通过定义ForeignKey可以给c_accnt赋值,也可以将父对象赋给accnt。在

在内部,sqlalchemy启动您在primaryjoin中编写的查询。若并没有外键,那个么模型就无法理解它必须在哪个字段上运行查询。在

你可以用任何两种方式。但我个人更喜欢ForeignKey和{},而不是{}。这样,您必须编写更多的代码,但是,这将为直接赋值和对象提供灵活性。在

我认为您的代码应该自动反映ForeignKey并用于关系而不做任何更改。
不过,还是有一些想法来探讨这个问题:

  1. 确保没有多个ForeignKey到同一父表,否则必须使用primaryjoin参数指定联接条件,因为SA无法自动决定使用哪一个。在
  2. 确保在slorder表中定义了ForeignKey(如代码示例所示)
  3. 检查是否为某些表定义了一个非默认的schema,也许你需要在你的表中定义一个_table_args__ = {'schema': 'my_schema'}(只是猜测,因为我不知道firebird,所以根本不知道那里有什么模式支持)
  4. 检查/调试反射步骤:sqlalchemy/dialects/firebird/base.pyget_foreign_keys。检查SQL语句fkqry,并直接在数据库上执行它,看看它是否反映了您的ForeignKey。如果没有,试着找出原因。在

相关问题 更多 >

    热门问题