SQLAlchemy и внешние ключи в отраженных таблицах - PullRequest
1 голос
/ 08 января 2020

Я немного застрял с проблемой, связанной с SQLAlchemy и отраженными таблицами, которые связаны с внешним ключом.

У меня есть две таблицы:

result_table:
=============
| id | team_home | team_visitor | result |
| -- | --------- | ------------ | ------ |
|  1 |         1 |            2 |    3:2 |
|  2 |         1 |            3 |    2:0 |

team_table:
===========
| id | team_name |
| -- | --------- |
|  1 | Hawks     |
|  2 | Sparrows  |
|  3 | Eagles    |

Теперь, эти таблицы уже существуют в базе данных. Я создал их с помощью PGAdmin и наполнил их образцами данных. team_home и team_visitor оба являются внешними ключами, указывающими на team_table.id.

В SQLAlchemy я использую декларацию для их отражения:

from sqlalchemy import MetaData, Table, create_engine
from sqlalchemy.engine.url import URL
from sqlalchemy.ext.declarative import declarative_base

database = {
            ...
           }

engine = create_engine(URL(**database))

Base = declarative_base()
meta = MetaData()

class Results(Base):
    __table__ = Table('result_table', meta, autoload=True, autoload_with=engine)

class Teams(Base):
    __table__ = Table('team_table', meta, autoload=True, autoload_with=engine)

Запрос к каждой таблице не является проблемой, но я не могу присоединиться к ним. Оператор наподобие session.query(Results, Teams).join(Teams).all() приведет к AmbiguousForeignKeysError.

Результат должен быть:

| id | team_home | team_visitor | result |
| -- | --------- | ------------ | ------ |
|  1 | Hawks     | Sparrows     |    3:2 |
|  2 | Hawks     | Eagles       |    2:0 |

Просмотр очищенных метаданных Я вижу, что внешний ключ загружен. Теперь я застрял. Я уверен, что мне не хватает столбца в моем классе, в котором объявляются отношения (например, relationship("Address", foreign_keys=[billing_address_id])), но, поскольку определение этого класса отражено, имена внешних ключей не доступны во время вызова (или во время создания экземпляра).

В любом случае, есть ли какие-то подсказки извне о том, как заставить внешние ключи работать в отраженных таблицах? Или лучше переопределить определение таблицы в своем классе?

Большое спасибо за ваше терпение.

С уважением, Томас

ОБНОВЛЕНИЕ

Намного проще использовать только основные функциональные возможности SQLAlchemy:

# database connection expected for this example

from sqlalchemy import MetaData
from sqlalchemy.sql import select, alias
import pandas as pd

metadata = MetaData()
metadata.reflect(bind=engine)

res_table = metadata.tables['result_table']
tt_home = metadata.tables['team_table'].alias('team_table_home')
tt_vis = metadata.tables['team_table'].alias('team_table_visitor')

s = select([
    res_table.c.id, 
    tt_home.c.team_name, 
    tt_vis.c.team_name,
    res_table.c.result
    ]).select_from(
        res_table.join(
            tt_home, res_table.c.team_home == tt_home.c.id
        ).join(
            tt_vis, res_table.c.team_visitor == tt_vis.c.id)
    ).order_by(res_table.c.id)

result_df = pd.read_sql_query(s, engine).set_index('id')

Надеюсь, это может помочь кому-то еще, когда вы столкнетесь с объединением двух таблиц, связанных двумя внешними ключами.

Ура, Томас

Ответы [ 2 ]

1 голос
/ 08 января 2020

Вы можете попробовать это -

session.query(Results, Teams).join(Teams, Teams.id==Results.team_home).all()
0 голосов
/ 08 января 2020

не уверен, является ли это источником вашей проблемы, поскольку вы говорите, что ваши метаданные загружаются правильно, но я сразу же загружаю метаданные с аргументом bind = engine

metadata = db.MetaData(bind=engine)

db - это объект sqlalchemy.

Я также загружаю таблицы без класса и просто делаю ссылку на него следующим образом:

results_table = db.Table('result_table', metadata, autoload=True)

без аргумента autoload_with = engine.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...