2014-12-04 3 views
6

Я пытаюсь понять, как делать соединения с составными внешними ключами в SQLAlchemy, и мои попытки сделать это терпят неудачу.SQLAlchemy соединяется с составными внешними ключами (с фляжкой-sqlalchemy)

У меня есть следующие классы модели на моей игрушечной модели (я использую колбовую SQLAlchemy, но я не уверен, что это не имеет ничего общего с этой проблемой):

# coding=utf-8 
from flask import Flask 
from flask.ext.sqlalchemy import SQLAlchemy 

app = Flask(__name__) 
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' 
db = SQLAlchemy(app) 


class Asset(db.Model): 
    __tablename__ = 'asset' 
    user = db.Column('usuario', db.Integer, primary_key=True) 
    profile = db.Column('perfil', db.Integer, primary_key=True) 
    name = db.Column('nome', db.Unicode(255)) 

    def __str__(self): 
     return u"Asset({}, {}, {})".format(self.user, self.profile, self.name).encode('utf-8') 


class Zabumba(db.Model): 
    __tablename__ = 'zabumba' 

    db.ForeignKeyConstraint(
     ['asset.user', 'asset.profile'], 
     ['zabumba.user', 'zabumba.profile'] 
    ) 

    user = db.Column('usuario', db.Integer, primary_key=True) 
    profile = db.Column('perfil', db.Integer, primary_key=True) 
    count = db.Column('qtdade', db.Integer) 

    def __str__(self): 
     return u"Zabumba({}, {}, {})".format(self.user, self.profile, self.count).encode('utf-8') 

Я тогда населяли база данных с некоторыми поддельные данные:

db.drop_all() 
db.create_all() 

db.session.add(Asset(user=1, profile=1, name=u"Pafúncio")) 
db.session.add(Asset(user=1, profile=2, name=u"Skavurska")) 
db.session.add(Asset(user=2, profile=1, name=u"Ermengarda")) 

db.session.add(Zabumba(user=1, profile=1, count=10)) 
db.session.add(Zabumba(user=1, profile=2, count=11)) 
db.session.add(Zabumba(user=2, profile=1, count=12)) 

db.session.commit() 

И попробовал следующий запрос:

> for asset, zabumba in db.session.query(Zabumba).join(Asset).all(): 
>  print "{:25}\t<---->\t{:25}".format(asset, zabumba) 

B ут SQLAlchemy говорит мне, что он не может найти адекватные внешние ключи для этого соединения:

Traceback (most recent call last): 
    File "sqlalchemy_join.py", line 65, in <module> 
    for asset, zabumba in db.session.query(Zabumba).join(Asset).all(): 
    File "/home/calsaverini/.virtualenvs/recsys/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 1724, in join 
    from_joinpoint=from_joinpoint) 
    File "<string>", line 2, in _join 
    File "/home/calsaverini/.virtualenvs/recsys/local/lib/python2.7/site-packages/sqlalchemy/orm/base.py", line 191, in generate 
    fn(self, *args[1:], **kw) 
    File "/home/calsaverini/.virtualenvs/recsys/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 1858, in _join 
    outerjoin, create_aliases, prop) 
    File "/home/calsaverini/.virtualenvs/recsys/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 1928, in _join_left_to_right 
    self._join_to_left(l_info, left, right, onclause, outerjoin) 
    File "/home/calsaverini/.virtualenvs/recsys/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2056, in _join_to_left 
    "Tried joining to %s, but got: %s" % (right, ae)) 
sqlalchemy.exc.InvalidRequestError: Could not find a FROM clause to join from. Tried joining to <class '__main__.Asset'>, but got: Can't find any foreign key relationships between 'zabumba' and 'asset'. 

Я попробовал несколько других вещей, как: объявление ForeignKeyConstraint на обеих таблицах или переворачивания запрос db.session.query(Asset).join(Zabumba).all().

Что я делаю неправильно?

Спасибо.


PS: В моем реальном коде приложения проблема на самом деле немного сложнее, потому что эти таблицы по различным схемам, и я буду использовать для привязки вещь:

app.config['SQLALCHEMY_BINDS'] = { 
    'assets':  'mysql+mysqldb://fooserver/assets', 
    'zabumbas':  'mysql+mysqldb://fooserver/zabumbas', 
} 

И тогда я Объявляем различные привязки к таблицам. Как я должен объявить ForeignKeyConstraint?

ответ

5

Ваш код содержит несколько опечаток, исправление которых сделает весь код работой.

Определить правильно в ForeignKeyConstraint:

  • это не просто определить его, вы должны добавить его в __table_args__
  • определение из колонн и refcolumns параметры сторнируется (см documentation)
  • имена столбцов должны быть именами в базе данных, а не атрибутами ORM

, как показано в следующем коде:

class Zabumba(db.Model): 
    __tablename__ = 'zabumba' 

    __table_args__ = (
     db.ForeignKeyConstraint(
      ['usuario', 'perfil'], 
      ['asset.usuario', 'asset.perfil'], 
     ), 
    ) 

конструкции должным образом запросе, имея оба класса в предложении запроса:

for asset, zabumba in db.session.query(Asset, Zabumba).join(Zabumba).all(): 
     print "{:25}\t<---->\t{:25}".format(asset, zabumba) 
Смежные вопросы