Как добавить автоматический фильтр к отношению с помощью SQLAlchemy?
-
06-07-2019 - |
Вопрос
Я использую SQLAlchemy 0.5rc, и я хотел бы добавить автоматический фильтр к отношению, чтобы каждый раз, когда он пытался извлечь записи для этого отношения, он игнорировал "удаленные" записи, если они помечены как "logically_deleted" (логическое поле дочерней таблицы)
Например, если объект "родительский" имеет отношение "дочерний", которое имеет
3 записи, но одна из них логически удалена, когда я запрашиваю "Родительский", я бы хотел, чтобы SQLA
извлекала родительский объект только с двумя дочерними объектами..
Как я должен это сделать?Путем добавления условия "и" к параметру primaryjoin
отношения?(например,"Children.parent_id == Parent.id and Children.logically_deleted == False
", но правильно ли писать "и" таким образом?)
Редактировать:
Мне удалось сделать это таким образом
children = relation("Children", primaryjoin=and_(id == Children.parent_id, Children.logically_deleted==False))
но есть ли способ использовать string в качестве primaryjoin вместо этого?
Решение
Функция and_() является правильным способом выполнения логических соединений в SQLAlchemy вместе с оператором &, но будьте осторожны с последним, поскольку он имеет неожиданные правила приоритета, т.е.более высокий приоритет, чем у операторов сравнения.
Вы также могли бы использовать строку в качестве основного соединения с конструктором text(), но это приведет к разрыву вашего кода при любом псевдонимировании таблицы, которое поставляется с eagerloading и joins.
Для логического удаления, возможно, было бы лучше сопоставить весь класс с select, который игнорирует удаленные значения:
mapper(Something, select([sometable], sometable.c.deleted == False))
Другие советы
но есть ли способ использовать string в качестве primaryjoin вместо этого?
Вы можете использовать следующее:
children = relationship("Children", primaryjoin="and_(Parent.id==Children.parent_id, Children.logically_deleted==False)"
У меня это сработало!
В настоящее время я разрабатываю только agains 0.4.something, но вот как я бы это предложил:
db.query(Object).filter(Object.first==value).filter(Object.second==False).all()
Я думаю, это то, что вы пытаетесь сделать, не так ли?
(Примечание:написано в веб-браузере, а не в реальном коде!)