实现标题几乎相当于How to use a labelled column in sqlalchemy filter?我认为这是一个单独的问题。
大大简化我的问题:假设我有两个查询,每个查询返回我想要的结果的一部分,我联合在一起:
initial_task = "initial_task"
scheduled_task = "scheduled_task"
initial = session.query(Task.task_id,
User.signup_date.label('due_date'),
literal(initial_task).label('type'))\
.join(Task.user)
schedule = session.query(Task.task_id,
Schedule.due_date.label('due_date'),
literal(scheduled_task).label('type'))\
.join(Task.schedule)
tasks = initial.union_all(schedule)
要明确:我意识到这个例子可以在没有结合的情况下重写;我的实际用例有五个单独的查询,在结果之外几乎没有任何共同点可以强制解释为这种正常格式。
如何过滤tasks
仅包含2017年4月1日之后到期的任务?从概念上讲,类似于:
tasks.filter(tasks.c.due_date >= datetime(2017, 4, 1))
主要问题是我无法弄清楚如何以一般方式引用due_date
列。我从文档中尝试的所有内容似乎都在讨论较低级别的API,而在ORM层上则会导致:
'Query' object has no attribute 'c'
答案 0 :(得分:1)
Query.union_all()
方法生成一个新的Query
实例,与sql.expression.union_all()
结构生成的CompoundSelect
略有不同,正如您所指出的那样。您可以使用literal_column()
过滤查询:
In [18]: tasks.filter(literal_column('due_date') >= datetime(2017, 4, 1))
Out[18]: <sqlalchemy.orm.query.Query at 0x7f1d2e191b38>
In [19]: print(_)
SELECT anon_1.task_id AS anon_1_task_id, anon_1.due_date AS anon_1_due_date, anon_1.type AS anon_1_type
FROM (SELECT task.id AS task_id, user.signup_date AS due_date, ? AS type
FROM task JOIN user ON task.id = user.task_id UNION ALL SELECT task.id AS task_id, schedule.due_date AS due_date, ? AS type
FROM task JOIN schedule ON task.id = schedule.task_id) AS anon_1
WHERE due_date >= ?
另一方面,您可以在各自的日期列中单独过滤联合的各个部分。
最后,你可以将你的联盟包装在一个子查询中,如果它更接近你的实际目标(由你的简化例子隐藏):
In [26]: tasks_sq = tasks.subquery()
In [27]: session.query(tasks_sq).\
...: filter(tasks_sq.c.due_date >= datetime(2017, 4, 1))
Out[27]: <sqlalchemy.orm.query.Query at 0x7f1d2e1d4828>
In [28]: print(_)
SELECT anon_1.task_id AS anon_1_task_id, anon_1.due_date AS anon_1_due_date, anon_1.type AS anon_1_type
FROM (SELECT anon_2.task_id AS task_id, anon_2.due_date AS due_date, anon_2.type AS type
FROM (SELECT task.id AS task_id, user.signup_date AS due_date, ? AS type
FROM task JOIN user ON task.id = user.task_id UNION ALL SELECT task.id AS task_id, schedule.due_date AS due_date, ? AS type
FROM task JOIN schedule ON task.id = schedule.task_id) AS anon_2) AS anon_1
WHERE anon_1.due_date >= ?