SQLAlchemy 2 外键相同的主键

发布于 2025-01-03 20:48:25 字数 1711 浏览 1 评论 0原文

我有一个带有 2 个外键的表,它们映射到另一个表的相同主键。我面临的问题是这两个外键可能是独立的值,但是,在使用 SQLAlchemy 时它们总是设置为相同的值。

表(短缺):

CREATE TABLE table1 (
  userid INT NOT NULL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  UNIQUE KEY(name)
);

CREATE TABLE table2 (
  taskid INT NOT NULL PRIMARY KEY,
  userid INT,
  ownerid INT,
  task VARCHAR(255) NOT NULL,
  FOREIGN KEY (userid) REFERENCES users (userid),
  FOREIGN KEY (ownerid) REFERENCES users (userid)
);

我正在使用 sqlalchemy 的经​​典映射器,我的类定义是:

class User:
  def __init__( self, name ):
    self.name = name

class Task:
  def __init__( self, task, ownerid ):
    self.task     = task
    self.ownerid  = ownerid

ownerid 和 userid 可能不同,即ownerid 是拥有任务的用户,userid 是创建任务的用户。

我已经创建了映射:

users_table = sqlalchemy.Table( 'users', self.metadata, autoload=True )
tasks_table = sqlalchemy.Table( 'tasks', self.metadata, autoload=True )

sqlalchemy.orm.mapper( User, users_table, properties= {
  'tasks': sqlalchemy.orm.relationship(Task) } )

sqlalchemy.orm.mapper( Task, tasks_table, properties {
  'user': sqlalchemy.orm.relationship( User, primaryjoin=tasks_table.c.userid==users_table.c.userid ),
  'owner': sqlalchemy.orm.relationship( User, primaryjoin=tasks_table.c.ownerid==users_table.c.userid ) } )

处理这些对象的语法类似于:

情况 1:

u1 = User('burt')
t1 = Task( 'buy milk', u1.userid )  # this case is that the task is assigned to self

情况 2:

u2 = User('kelly')
t2 = Task( 'review code', u1.userid )  # assign to burt, creator is kelly

在情况 2 中,我在这里遇到问题,因为所有者 ID 始终等于用户 ID,在此 在这种情况下,ownerid 和 userid 始终为 2(对于 kelly)。

i have a table with 2 foreign keys that map to the same primary key of another table. the problem i'm facing is that these two foreign keys could be independent values, however, they always get set to the same thing when using SQLAlchemy.

tables (shorthanded):

CREATE TABLE table1 (
  userid INT NOT NULL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  UNIQUE KEY(name)
);

CREATE TABLE table2 (
  taskid INT NOT NULL PRIMARY KEY,
  userid INT,
  ownerid INT,
  task VARCHAR(255) NOT NULL,
  FOREIGN KEY (userid) REFERENCES users (userid),
  FOREIGN KEY (ownerid) REFERENCES users (userid)
);

i'm using the classical mapper from sqlalchemy and my class definition is:

class User:
  def __init__( self, name ):
    self.name = name

class Task:
  def __init__( self, task, ownerid ):
    self.task     = task
    self.ownerid  = ownerid

the ownerid and userid could be different i.e. ownerid is the user who owns the task and userid is the user that created the task.

i've created mappings:

users_table = sqlalchemy.Table( 'users', self.metadata, autoload=True )
tasks_table = sqlalchemy.Table( 'tasks', self.metadata, autoload=True )

sqlalchemy.orm.mapper( User, users_table, properties= {
  'tasks': sqlalchemy.orm.relationship(Task) } )

sqlalchemy.orm.mapper( Task, tasks_table, properties {
  'user': sqlalchemy.orm.relationship( User, primaryjoin=tasks_table.c.userid==users_table.c.userid ),
  'owner': sqlalchemy.orm.relationship( User, primaryjoin=tasks_table.c.ownerid==users_table.c.userid ) } )

and the syntax for working with these objects is something akin to:

case 1:

u1 = User('burt')
t1 = Task( 'buy milk', u1.userid )  # this case is that the task is assigned to self

case 2:

u2 = User('kelly')
t2 = Task( 'review code', u1.userid )  # assign to burt, creator is kelly

in case 2, i'm having an issue here as the ownerid always equals the userid, in this
case the ownerid and userid are 2 (for kelly) always.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

瑶笙 2025-01-10 20:48:25

您必须使用 主要加入

因此,您的代码将像

# Connected to owner of the record.
sqlalchemy.orm.mapper( User, users_table, properties= {
  'tasks': sqlalchemy.orm.relationship(Task, primaryjoin="Task.ownerid==User.userid") } )

# Similarly you can create relation ship with creater.

注意:当您有2个具有相同表的外键时,您必须提及哪个关系引用依赖表中的哪个文件。

可能这会解决您的问题

You have to use primaryjoin.

So your code will be change like

# Connected to owner of the record.
sqlalchemy.orm.mapper( User, users_table, properties= {
  'tasks': sqlalchemy.orm.relationship(Task, primaryjoin="Task.ownerid==User.userid") } )

# Similarly you can create relation ship with creater.

Note: When you have 2 foreign key with same table then you have to mention which relation is refer to which filed in the dependent table.

Might be this will solve your problem

温柔一刀 2025-01-10 20:48:25

我有一个修复:我刚刚向 Task 添加了一个 owner 成员变量:

class Task:

  owner  = None

  def __init__( Self, task ):
    self.task = task`

然后:

u1 = User('Burt')
u2 = User('Kelly')
t1 = Task('get newspaper')
u1.task.append(t1) # creator of the task
t1.owner = u2 # owner of the task

I have a fix: I just added an owner member variable to Task:

class Task:

  owner  = None

  def __init__( Self, task ):
    self.task = task`

and then:

u1 = User('Burt')
u2 = User('Kelly')
t1 = Task('get newspaper')
u1.task.append(t1) # creator of the task
t1.owner = u2 # owner of the task
秉烛思 2025-01-10 20:48:25

当同一个表有多个关系时,sqlalchemy 需要更多信息来了解如何构建连接。您可以使用 primaryjoinforeign_keys 来实现这一点。正如 Lafada 提到的,任务关系缺少这一额外的信息。

我的代码版本没有显示您提到的问题。也许您可以检查一下这是否可以解决您的问题?

from sqlalchemy import create_engine, MetaData, Table
from sqlalchemy.orm import relationship, mapper, clear_mappers
engine = create_engine('sqlite:///:memory:', echo=True)
conn = engine.connect()

# create tables manually so simulate question
conn.execute("""
CREATE TABLE users (
  userid INT NOT NULL PRIMARY KEY,
  name VARCHAR(255) NOT NULL
)""")

conn.execute("""
CREATE TABLE tasks (
  taskid INT NOT NULL PRIMARY KEY,
  userid INT,
  ownerid INT,
  task VARCHAR(255) NOT NULL,
  FOREIGN KEY (userid) REFERENCES users (userid),
  FOREIGN KEY (ownerid) REFERENCES users (userid)
)""")

# create classes and mappings
class User:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name

class Task:
    def __init__(self, task, owner=None, user=None):
        self.task = task
        self.owner = owner
        self.user = user
    def __repr__(self):
        return self.task

metadata = MetaData(bind=engine)
users_table = Table( 'users', metadata, autoload=True )
tasks_table = Table( 'tasks', metadata, autoload=True )

clear_mappers()

mapper( User, users_table, properties= {
  'tasks': relationship(Task, primaryjoin=tasks_table.c.userid==users_table.c.userid  ) } )

mapper( Task, tasks_table, properties= {
  'user': relationship( User, primaryjoin=tasks_table.c.userid==users_table.c.userid ),
  'owner': relationship( User, primaryjoin=tasks_table.c.ownerid==users_table.c.userid ) } )

# test
u1 = User('burt')
t1 = Task( 'buy milk', u1, u1)
print('%s, user=%s, owner=%s' % (t1, t1.user, t1.owner))

u2 = User('kelly')
t2 = Task( 'review code', u1, u2)
print('%s, user=%s, owner=%s' % (t2, t2.user, t2.owner))

When you have more than one relationship to the same table, sqlalchemy need more information to find out how to build the join. You can use either primaryjoin or foreign_keys to achieve that. As Lafada mentioned, the Task relationship is missing this extra bit of information.

My version of your code does not display the problem you mentioned. Maybe you could check and see if this solves your problem?

from sqlalchemy import create_engine, MetaData, Table
from sqlalchemy.orm import relationship, mapper, clear_mappers
engine = create_engine('sqlite:///:memory:', echo=True)
conn = engine.connect()

# create tables manually so simulate question
conn.execute("""
CREATE TABLE users (
  userid INT NOT NULL PRIMARY KEY,
  name VARCHAR(255) NOT NULL
)""")

conn.execute("""
CREATE TABLE tasks (
  taskid INT NOT NULL PRIMARY KEY,
  userid INT,
  ownerid INT,
  task VARCHAR(255) NOT NULL,
  FOREIGN KEY (userid) REFERENCES users (userid),
  FOREIGN KEY (ownerid) REFERENCES users (userid)
)""")

# create classes and mappings
class User:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name

class Task:
    def __init__(self, task, owner=None, user=None):
        self.task = task
        self.owner = owner
        self.user = user
    def __repr__(self):
        return self.task

metadata = MetaData(bind=engine)
users_table = Table( 'users', metadata, autoload=True )
tasks_table = Table( 'tasks', metadata, autoload=True )

clear_mappers()

mapper( User, users_table, properties= {
  'tasks': relationship(Task, primaryjoin=tasks_table.c.userid==users_table.c.userid  ) } )

mapper( Task, tasks_table, properties= {
  'user': relationship( User, primaryjoin=tasks_table.c.userid==users_table.c.userid ),
  'owner': relationship( User, primaryjoin=tasks_table.c.ownerid==users_table.c.userid ) } )

# test
u1 = User('burt')
t1 = Task( 'buy milk', u1, u1)
print('%s, user=%s, owner=%s' % (t1, t1.user, t1.owner))

u2 = User('kelly')
t2 = Task( 'review code', u1, u2)
print('%s, user=%s, owner=%s' % (t2, t2.user, t2.owner))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文