微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将 sqlalchemy 查询过滤到所有没有孩子的父母和所有父母,他们属于 Flask 表单中的条件

如何解决如何将 sqlalchemy 查询过滤到所有没有孩子的父母和所有父母,他们属于 Flask 表单中的条件

首先,我对编码很陌生,如果不值得关注,请提前道歉。

我处理一对多关系。假设我有一个 Parent 类和一个 Child 类,定义如下:

class Parent(db.Model):
    __tablename__ = 'parent'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(128),nullable = False)   
    age = db.Column(db.Integer(32),nullable = False) 
    children = db.relationship('Child',backref='parent',lazy='dynamic')


class Child(db.Model):
    __tablename__ = 'child'
    id = db.Column(db.Integer,primary_key=True)
    parent_id = db.Column(db.Integer,db.ForeignKey('parent.id'),nullable = False) 
    weight = db.Column(db.Integer(32),nullable = False)

我想要做的是外连接表格并显示所有父母的信息(姓名、年龄):

  1. 要么不要孩子
  2. 或者父母和孩子都满足之前通过 Flask 表单输入的条件(用户提交一个范围(假设孩子的最小和最大体重以及年龄相同))。如果他们至少有一个孩子满足条件并且父母自己满足条件,则父母会出现在结果中。

我成功获得了满足 1 或 2 的查询。这些查询

#1 有效!

parentssql=session.query(Parent,Child)\
.outerjoin(Child)\
.filter(Child.id == None)\
.distinct(Parent.name)\
.group_by(Parent.name)\
.order_by(Parent.name)\
.all()

#2 也能用!

parents=session.query(Parent,Child)\
.outerjoin(Child)\
.filter(Parent.age.between(form.age_min.data,form.age_max.data),Child.weight.between(form.weight_min.data,form.weight_max.data))\
.distinct(Parent.name)\
.group_by(Parent.name)\
.order_by(Parent.name)\
.all()

那么如何在不进行过多查询的情况下将它们组合起来(基本上尽可能高效(问号))

谢谢!

编辑 1:

我尝试使用 orand 条件,但它给了我一个错误。首先,我将添加我编辑过的代码(最初是关于星系和线检测)

编辑后的查询

galaxies=session.query(galaxy,Line)\
.outerjoin(Line)\
.filter(galaxy.name.contains(form_advanced.name.data) \
& (galaxy.right_ascension.between(form_advanced.right_ascension_min.data,form_advanced.right_ascension_max.data) | galaxy.right_ascension == None ) \
& (galaxy.declination.between(form_advanced.declination_min.data,form_advanced.declination_max.data) | galaxy.declination == None ) \
& (galaxy.redshift.between(form_advanced.redshift_min.data,form_advanced.redshift_max.data) | galaxy.redshift == None ) \
& (galaxy.lensing_flag.contains(form_advanced.lensing_flag.data) | galaxy.lensing_flag == None))

这里是我添加条件的地方 (Child.id == None) | (条件 1 & 条件 2 & ...)

galaxies = galaxies.filter((Line.id == None) | ((Line.j_upper.between(form_advanced.j_upper_min.data,form_advanced.j_upper_max.data) | Line.j_upper == None ) \
& (Line.line_id_type.contains(form_advanced.line_id_type.data) | Line.line_id_type == None) \
& (Line.integrated_line_flux.between(form_advanced.integrated_line_flux_min.data,form_advanced.integrated_line_flux_max.data) | Line.integrated_line_flux == None) \
& (Line.peak_line_flux.between(form_advanced.peak_line_flux_min.data,form_advanced.peak_line_flux_max.data) | Line.peak_line_flux == None) \
& (Line.line_width.between(form_advanced.line_width_min.data,form_advanced.line_width_max.data) | Line.line_width == None ) \
& (Line.observed_line_frequency.between(form_advanced.observed_line_frequency_min.data,form_advanced.observed_line_frequency_max.data) | Line.observed_line_frequency == None ) \
& (Line.detection_type.contains(form_advanced.detection_type.data) | Line.detection_type == None) \
& (Line.observed_beam_major.between(form_advanced.observed_beam_major_min.data,form_advanced.observed_beam_major_max.data) | Line.observed_beam_major == None ) \
& (Line.observed_beam_minor.between(form_advanced.observed_beam_minor_min.data,form_advanced.observed_beam_minor_max.data) | Line.observed_beam_minor == None ) \
& (Line.reference.contains(form_advanced.reference.data),Line.reference == None) ))
galaxies = galaxies.distinct(galaxy.name).group_by(galaxy.name).order_by(galaxy.name).all()

这就是我得到的错误

sqlalchemy.exc.ArgumentError: sql expression for WHERE/HAVING role expected,got (<sqlalchemy.sql.elements.BinaryExpression object at 0x7f381585b790>,<sqlalchemy.sql.elements.BinaryExpression object at 0x7f3814eb6670>).

编辑 2

解决了该问题并使其与下面@vitaliy 的评论一起工作!

解决方法

您可以向 filter 函数加入更多条件,然后使用 or_and_

parents = session.query(Parent,Child)\
.outerjoin(Child)\
.filter(or_(and_(Parent.age.between(age_min,age_max),Child.weight.between(weight_min,weight_max)),Child.id == None))\
.distinct(Parent.name)\
.group_by(Parent.name)\
.order_by(Parent.name)\
.all()

我不确定您代码中 or_ 背后的意图是什么,但现在它什么也不做,因为只有一个参数传递给 or_ 函数。 如果您的意思是 Child.weight Parent.age 应满足提供的条件,那么您的过滤器应如下所示:

filter(or_(Parent.age.between(age_min,age_max) Child.weight.between(weight_min,weight_max),Child.id == None))

我还建议让您的代码少一些冗余,多一些 Pythonic:

parents = session.query(Parent).outerjoin(Child)\
  .filter((Parent.age.between(age_min,age_max) & Child.weight.between(weight_min,weight_max)) | (Child.id == None))\
  .order_by(Parent.name)\
  .all()
,

试试Query.union示例:文档中的逐字逐句:

q1 = sess.query(SomeClass).filter(SomeClass.foo=='bar')
q2 = sess.query(SomeClass).filter(SomeClass.bar=='foo')

q3 = q1.union(q2)

在您的情况下,您应该在执行 .all() 之前删除 union
而且我还会考虑对结果查询只执行一次 .order_by(..)
我还认为不需要 .distinct(Parent.name),因为您已经做了 .group_by(Parent.name) 将删除重复项。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。