Есть две модели SQLAlchemy:
class User(Base):
__tablename__ = 'user'
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, index=True)
username: Mapped[str] = mapped_column(String(32), unique=True, index=True)
sanctions: Mapped[list['UserSanction']] = relationship(
'UserSanction', back_populates='user', foreign_keys='[UserSanction.user_id]')
applied_sanctions: Mapped[list['UserSanction']] = relationship(
'UserSanction', back_populates='moder', foreign_keys='[UserSanction.moder_id]')
class UserSanction(Base):
__tablename__ = 'user_sanction'
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, index=True)
user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey(User.id))
moder_id: Mapped[int] = mapped_column(BigInteger, ForeignKey(User.id))
reason: Mapped[Optional[str]] = mapped_column(String(64))
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
user: Mapped[User] = relationship(back_populates='sanctions', cascade='all,delete', foreign_keys=[user_id])
moder: Mapped[User] = relationship(back_populates='applied_sanctions', foreign_keys=[moder_id])
Нужно каким-то образом получить пользователя по юзернейму, да так, чтобы на выходе был объект User с полем
User.sanctions: list[UserSanction]
(санкции отфильтрованы по полю is_active - должно быть True), в каждой санкции чтобы также присутствовало ещё и поле moder, являющееся объектом класса User. Представлю желаемый результат в JSON, чтобы было понятнее:
{
"id": 1,
"username": "user1",
"sanctions": [
{
"id": 1,
"moder": {
"id": 2,
"username": "Moderator228"
},
"reason": "...",
"is_active": true
},
{
"id": 2,
"moder": {
"id": 3,
"username": "MisterAdmin"
},
"reason": "...",
"is_active": true
},
]
}
Возможно ли это выполнить одним запросом к базе? И, если да, то как это сделать через ORM?
UPD:
Вот такой запрос получилось составить (PostgreSQL), который выполняет все условия, однако как это перенести в ORM?
WITH desired_user AS (
SELECT id
FROM "user"
WHERE username = '________'
)
SELECT u.id AS user_id, u.username,
s.id AS sanction_id, s.user_id AS sanction_user_id, s.moder_id AS sanction_moder_id, s.is_active AS sanction_is_active,
m.id AS moder_id, m.username AS moder_username
FROM desired_user du
JOIN "user_sanction" s ON du.id = s.user_id AND s.is_active = true
LEFT JOIN "user" u ON du.id = u.id
LEFT JOIN "user" m ON s.moder_id = m.id;