У меня есть SQLAlchemy декларативную модель, которая выглядит следующим образом:Почему это выражение sqlalchemy or_ не работает с истинным предложением?
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(32), unique=True, nullable=False)
posts = relationship('Post', cascade='all, delete-orphan', back_populates='owner')
class Post(Base):
__tablename__ = 'post'
id = Column(Integer, primary_key=True)
owner_id = Column(Integer, ForeignKey('user.id', ondelete="CASCADE"), nullable=False)
name = Column(String(256), nullable=False)
public = Column(Boolean, default=True)
owner = relationship('User', back_populates='posts', single_parent=True)
shared = relationship('User', secondary=shared_post)
В моей тестовой базе данных, у меня есть пользователь User1, который имеет пост Post1. У Post1 нет связанных с ним общих пользователей. Я попробовал запрос:
expr = or_(Post.owner == current_user, # current_user is ORM User1
Post.public == True,
Post.shared.contains(another_user))
posts = session.query(Post).filter(expr).all()
Однако posts
является пустым списком. Вот отдельные запросы:
session.query(Post).filter(Post.owner == current_user).all() # returns Post1
session.query(Post).filter(Post.public == True).all() # returns Post1
session.query(Post).filter(Post.shared.contains(another_user)).all() # empty list as expected
Почему не оригинальный or_
работы, если два из трех отдельных запросов подтвердятся работает?
Edit # 1:
Замена Post.shared.contains(another_user)
с Post.shared.any(User.id == another_user_id)
исправляет проблему or_
запроса. Однако теперь я хотел бы знать, почему один работает, а другой нет.
Спасибо за ответ и советы отладки в глубину. Скажете ли вы, что исходный запрос 'or_' работает так, как предполагалось, или если sqlalchemy вставили круглые скобки вокруг' .contains() '? – trianta2
@ trianta2 интуитивно чувствовал, что он должен иметь круглые скобки. Чтение того, что ['RelationshipProperty.Comparator.contains'] (http://docs.sqlalchemy.org/en/rel_1_0/orm/internals.html#sqlalchemy.orm.properties.RelationshipProperty.Comparator.contains) должно дополнять это чувство , но, с другой стороны, в этом случае из-за объединения он все равно потерпит неудачу и как таковой будет неправильным выбором. '' '' '' '' '', Который вы сами выяснили, выдает правильное выражение 'EXISTS'. –
Связанная документация фактически перечисляет этот точный случай как предостережение об использовании 'contains()' с отношениями «многие ко многим». Он не будет работать со сложными выражениями OR и т. Д. –