ForeignKeys & JOIN - не работает запрос

Такая проблема, использую PostgreSQL & GINO и сейчас пытаюсь в джоины.

У меня имеются две модели, Game & User. Пытаюсь выбрать игры, в которых:

  1. Нет противника
  2. Такая же валюта игры
  3. Опыт хоста игры больше или меньше заданного промежутка.

Должен получиться примерно такой запрос (написан на MySQL мне нужно переписать под PostgreSQL):

SELECT g.id       AS id_0,
       g.currency AS currency_1,
       g.user_id   AS user_id
FROM games g
         INNER JOIN users u1_ ON g.user_id = u1_.id
WHERE (u1_.experience BETWEEN ? AND ?)
  AND g.currency = ?
  AND g.enemy_id IS NULL
  AND g.winner_id IS NULL
ORDER BY g.id ASC

Делаю запрос так:

async def find_pending_game(user: User, currency: str):
    ...
    return await Game.join(User).select().where(User.experience.between(min_experience, max_experience),
                                                         Game.currency == currency,
                                                         Game.enemy_id is None,
                                                         Game.winner_id is None).all()

Модели: user.py

from __future__ import annotations

from sqlalchemy.sql import expression

from app.models.db import BaseModel, TimedBaseModel, db


class User(TimedBaseModel):
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True, index=True, unique=True)
    ...

class UserRelatedModel(BaseModel):
    __abstract__ = True

    user_id = db.Column(
        db.ForeignKey(f"{User.__tablename__}.id", ondelete="CASCADE", onupdate="CASCADE"),
        nullable=False,
    )

game.py

from __future__ import annotations

from app.models.db import BaseModel, TimedBaseModel, db


class Game(TimedBaseModel):
    __tablename__ = "games"

    id = db.Column(db.Integer, primary_key=True, index=True, unique=True)

    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    stock_id = db.Column(db.Integer, db.ForeignKey('stocks.id'))
    enemy_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    enemy_stock_id = db.Column(db.Integer, db.ForeignKey('stocks.id'))
    winner_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    ...


class GameRelatedModel(BaseModel):
    __abstract__ = True

    game_id = db.Column(
        db.ForeignKey(f"{Game.__tablename__}.id", ondelete="CASCADE", onupdate="CASCADE"),
        nullable=False,
    )

db.py

import datetime
from typing import List

import sqlalchemy as sa
from gino import Gino

from app import config

db = Gino()


class BaseModel(db.Model):
    __abstract__ = True

    def __str__(self):
        model = self.__class__.__name__
        table: sa.Table = sa.inspect(self.__class__)
        primary_key_columns: List[sa.Column] = table.primary_key.columns
        values = {
            column.name: getattr(self, self._column_name_map[column.name])
            for column in primary_key_columns
        }
        values_str = " ".join(f"{name}={value!r}" for name, value in values.items())
        return f"<{model} {values_str}>"


class TimedBaseModel(BaseModel):
    __abstract__ = True

    created_at = db.Column(db.DateTime(True), server_default=db.func.now())
    updated_at = db.Column(
        db.DateTime(True),
        default=datetime.datetime.utcnow,
        onupdate=datetime.datetime.utcnow,
        server_default=db.func.now(),
    )
...

Но в итоге получаю ошибку.

sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'games' and 'users'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.

В чём проблема?


Ответы (1 шт):

Автор решения: MyZik

Решил проблему:

await Game.join(User, User.id == Game.user_id).select().where(
        and_(
            between(User.experience, min_experience, max_experience),
            Game.currency == currency,
            Game.enemy_id == None,
            Game.winner_id == None
        )
    ).gino.all()
→ Ссылка