FastAPI использующее SQLAlchemy_2.0
Есть функция возвращающая Shift c загруженными предварительно связанными Member.user и Member.reports. Которая использует для этого рекомендованный метод selectinload Необходимо изменить её так, чтобы возвращались связанные данные только тех Member, у которых Member.user.is_test_user == False
Модели:
class Shift(Base):
__tablename__ = "shifts"
reports = relationship("Report", back_populates="shift")
members = relationship("Member", back_populates="shift")
class User(Base):
__tablename__ = "users"
members = relationship("Member", back_populates="user")
is_test_user = Column(Boolean, default=False, nullable=False)
class Member(Base):
__tablename__ = "members"
status = Column(String(10))
user_id = Column(UUID(as_uuid=True), ForeignKey(User.id), nullable=False)
user = relationship("User", back_populates="members")
shift_id = Column(UUID(as_uuid=True), ForeignKey(Shift.id), nullable=False)
shift = relationship("Shift", back_populates="members")
reports = relationship("Report", back_populates="member")
class Report(Base):
__tablename__ = "reports"
shift_id = Column(UUID(as_uuid=True), ForeignKey(Shift.id), nullable=False)
shift = relationship("Shift", back_populates="reports")
member_id = Column(UUID(as_uuid=True), ForeignKey(Member.id), nullable=False)
member = relationship("Member", back_populates="reports")
Функция:
async def get_with_members(self, id: UUID, member_status: Optional[str]) -> Shift:
member_stmt = Shift.members
if member_status:
member_stmt = member_stmt.and_(Member.user == member_status)
statement = (
select(Shift)
.where(Shift.id == id)
.options(selectinload(Shift.members).selectinload(Member.user))
.options(selectinload(Shift.members).selectinload(Member.reports))
)
request = await self._session.execute(statement)
return request.scalars().first()
Попытки изменить member_stmt == Shift.members.and_(Member.user.is_test_user==False), вызывают исключение: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Member.user has an attribute 'is_test_user'. Возможно необходимо использовать вместо selectinload() обычный join() совместно contains_eager() или subqueryload() ?
Кол на пастбин или гист, а то много, тут не воспринимается
https://pastebin.com/px0Pn7JY
Я бы сделал джоином
А не, ты хочешь чтобы при этом запросе в релейшене были отфильтрованы по полю?
Да необходимо отсечь тех Members у которых есть связь с User, который, в свою очередь имеет поле User.is_test_user == True
Тогда да, джоин и два условия в where
statement = ( select(Shift) .join(Shift.members) .where(Shift.id == id, User.is_test_user == False) .options(contains_eager(Shift.members)) ) Изменил statement таким образом, теперь раизится greenlet_spawn has not been called; can't call await_only() here. Was IO attempted in an unexpected place.
Обсуждают сегодня