![](/img/trans.png)
[英]How to filter an sqlalchemy query to all Parents w/o Children, and all Parents, who fall under conditions in a Flask Form
[英]SQLAlchemy query parents with ALL children matching a filter
我正在嘗試創建一個 sqlalchemy 查詢(flask-sqlalchemy),如果所有子項都匹配查詢而不是 ANY,則該查詢僅返回父對象。 IE
(Parent
.query
.join(Child)
.filter(Child.column == True)
).all()
將返回所有具有column == True
的子對象的所有父對象,我該如何編寫它以使所有子對象都必須具有column == True
?
上面的部分是從這個實際代碼中抽象出來的。 在哪里
家長 == 學生和孩子 == StudentApplication
model 層次結構如下:
用戶 ---> 學生 ---> StudentApplication
我正在嘗試檢索有學生但尚未提交申請的用戶,同時忽略至少有 1 名學生提交申請的用戶。
def _active_student_query(statement=None):
import sqlalchemy as sa
statement = statement or _active_user_query()
statement = statement.join(Student).filter(Student.suspended == sa.false())
return statement
def users_without_submitted_applications(exclude_contacted=False):
import sqlalchemy as sa
from sqlalchemy.orm.util import AliasedClass
# AppAlias = AliasedClass(StudentApplication)
has_any_approved_app = sa.exists(
sa.select([])
.select_from(Student)
.where((StudentApplication.student_id == Student.id) &
(StudentApplication.flags.op('&')(AppFlags.SUBMITTED) > 0),
)
)
statement = _active_student_query()
statement = (statement
# .join(StudentApplication)
# .filter(User.students.any())
# has a student and no submitted applications
.filter(~has_any_approved_app)
# .filter(StudentApplication.flags.op('&')(AppFlags.SUBMITTED) == 0)
)
if exclude_contacted:
statement = (statement
.join(AlertPreferences)
.filter(AlertPreferences.marketing_flags.op('&')(MarketingFlags.NO_APP_PING) == 0)
)
from lib.logger import logger
logger.info(statement.sql)
return statement
這是它生產的 SQL
SELECT users.is_active, users.flags, users.created_on, users.updated_on, users.id
FROM users JOIN student ON users.id = student.user_id
WHERE users.is_active = true AND student.suspended = false AND NOT (EXISTS (SELECT
FROM student_application
WHERE student_application.student_id = student.id AND (student_application.flags & %(flags_1)s) > %(param_1)s))
如果您正在尋找所有孩子都有column = TRUE
的父母,那么這相當於沒有孩子有column = FALSE
的所有父母。 如果您使用 JOIN,您會遇到每個孩子而不是每個父母擁有一行的問題。 因此,我建議改用WHERE EXISTS()
。 像這樣的查詢可以解決問題:
SELECT *
FROM parent
WHERE NOT EXISTS(
SELECT
FROM child
WHERE child.parent_id = parent.id
AND child.column = FALSE
)
在 Flask-SQLAlchemy 中,這變成:
import sqlalchemy as sa
has_any_false_children = sa.exists(
sa.select([])
.select_from(Child)
.where((Child.parent_id == Parent.id) &
(Child.column == sa.false()))
)
Parent.query.filter(~has_any_false_children)
更新
既然你在談論User
s,所有Student
s 都完成了所有StudentApplication
s,我認為它應該變成
student_has_any_non_approved_app = sa.exists(
sa.select([])
.select_from(StudentApplication)
.where((StudentApplication.student_id == Student.id) &
(StudentApplication.flags.op('&')(AppFlags.SUBMITTED) > 0) &
((StudentApplication.flags.op('&')(AppFlags.APPROVED) == 0) |
(StudentApplication.flags.op('&')(AppFlags.PARTIALLY_APPROVED) == 0)))
)
user_has_any_non_approved_students = sa.exists(
sa.select([])
.select_from(Student)
.where((Student.user_id == User.id) &
(Student.suspended == sa.false()) &
student_has_any_non_approved_app)
)
statement = (
_active_user_query()
.filter(User.students.any())
# has a student and no submitted applications
.filter(~user_has_any_non_approved_students)
)
這將返回所有用戶。 如果您隨后想要該用戶的學生,我會將其放入單獨的查詢中 - 並在那里應用營銷標志。
statement = Student.query.filter(
Student.user_id.in_(user_ids),
Student.suspended == sa.false()
)
if exclude_contacted:
statement = (statement
.join(AlertPreferences)
.filter(AlertPreferences.marketing_flags.op('&')(MarketingFlags.NO_APP_PING) == 0)
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.