简体   繁体   English

SQLAlchemy 2指向同一主键的外键

[英]SQLAlchemy 2 Foreign Keys to the same Primary Key

i have a table with 2 foreign keys that map to the same primary key of another table. 我有一个表有2个外键,映射到另一个表的相同主键。 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. 我面临的问题是这两个外键可以是独立的值,但是,使用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: 我正在使用sqlalchemy的经典映射器,我的类定义是:

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 ie ownerid is the user who owns the task and userid is the user that created the task. ownerid和userid可以是不同的,即ownerid是拥有该任务的用户,userid是创建该任务的用户。

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: 情况1:

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

case 2: 案例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. 在情况2中,我遇到了一个问题,因为ownerid始终等于userid,在这种情况下ownerid和userid始终为2(对于kelly)。

You have to use primaryjoin . 你必须使用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. 注意:当你有2个具有相同表的外键时,你必须提到哪个关系引用了从属表中的哪个。

Might be this will solve your problem 这可能会解决你的问题

I have a fix: I just added an owner member variable to Task : 我有一个解决方法:我刚刚向Task添加了一个owner成员变量:

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

When you have more than one relationship to the same table, sqlalchemy need more information to find out how to build the join. 当您对同一个表有多个关系时,sqlalchemy需要更多信息来了解如何建立联接。 You can use either primaryjoin or foreign_keys to achieve that. 您可以使用primaryjoinforeign_keys来实现此目的。 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))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM