![](/img/trans.png)
[英]SQLAlchemy multiple foreign keys in one mapped class to the same primary key
[英]SQLAlchemy 2 Foreign Keys to the same Primary Key
我有一个表有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 ) } )
使用这些对象的语法类似于:
u1 = User('burt')
t1 = Task( 'buy milk', u1.userid ) # this case is that the task is assigned to self
u2 = User('kelly')
t2 = Task( 'review code', u1.userid ) # assign to burt, creator is kelly
在情况2中,我遇到了一个问题,因为ownerid始终等于userid,在这种情况下ownerid和userid始终为2(对于kelly)。
你必须使用primaryjoin 。
因此您的代码将像
# 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个具有相同表的外键时,你必须提到哪个关系引用了从属表中的哪个。
这可能会解决你的问题
我有一个解决方法:我刚刚向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
当您对同一个表有多个关系时,sqlalchemy需要更多信息来了解如何建立联接。 您可以使用primaryjoin或foreign_keys来实现此目的。 正如拉法达所说,任务关系缺少这些额外的信息。
我的代码版本不显示您提到的问题。 也许您可以检查一下是否可以解决您的问题?
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))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.