SQLAlchemy 2 внешних ключа к тому же первичному ключу - PullRequest
1 голос
/ 09 февраля 2012

У меня есть таблица с 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 у меня возникла проблема, поскольку ownerid всегда равен идентификатору пользователя, в этом case для ownerid и userid всегда равны 2 (для Келли).

Ответы [ 3 ]

2 голосов
/ 10 февраля 2012

Вы должны использовать 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 внешних ключа с одной и той же таблицей, вам нужно указать, какое отношение относится к какой, поданной в зависимую таблицу. Может быть, это решит вашу проблему

1 голос
/ 11 февраля 2012

У меня есть исправление: я просто добавил owner переменную-член к Task:

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
0 голосов
/ 01 апреля 2014

Если у вас более одной взаимосвязи с одной и той же таблицей, 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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...