ForeignKeys & JOIN - не работает запрос
Такая проблема, использую PostgreSQL & GINO и сейчас пытаюсь в джоины.
У меня имеются две модели, Game & User. Пытаюсь выбрать игры, в которых:
- Нет противника
- Такая же валюта игры
- Опыт хоста игры больше или меньше заданного промежутка.
Должен получиться примерно такой запрос (написан на 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()