我正在使用sqlalchemy,我想从用户那里获取以下数据,并按照给表的顺序应用这些操作:
用于过滤数据的关键字,按顺序排序的列,限制和页面 数字
现在我有很多桌子。大多数“儿童”表(没有孩子的表)都可以工作。但是我有一张桌子,桌子上有很多各种各样的关系..双方一对一,一对一,多对多
为实现上述操作,我预先加入了所有表。过滤和排序工作正常,但限制不能给我想要的结果
加入声明:
records = m.Activity.query.join(m.Event, m.Activity.events) \
.join(m.DateLocation, m.Activity.date_locations) \
.join(m.Goal, m.Activity.goals) \
.join(m.Type, m.Activity.type)
过滤和排序包含许多不必要的信息,基本上是这样的:
# filtering if column == event
records = records.filter(m.Event.name == keyword)
# ordering if column == type and desc was chosen
records = records.order_by(m.Type.name.desc())
最后是限制和分页:
records = records.limit(limit)
records = records.offset((page - 1) * limit)
让我解释一下极限行为与我想要的东西
此代码中的limit工作正常。由于我联接了所有表,因此它将返回我给它的联接行的数目..如果联接导致额外的5行,并且我要求限制5,例如,它将返回前5个而不管原始表的ID >
我想要的是加入之前的极限行为。我只加入了他们以按他们筛选或订购。之后,当我说限制(5)时,我想返回前5个具有不同ID的结果
我尝试了以下操作(一次一次),但是没有用:
records = records.distinct(m.Activity.id).limit(limit)
records = records.group_by(m.Activity.id).limit(limit)
records = records.from_self().limit(limit)
我尝试了here提出的解决方案。无论如何,它在加入之前限制了数据集。在我的情况下不起作用,因为我需要限制过滤后的数据
编辑:模型:
EventsInActivities = db.Table(
'events_in_activities',
db.Column('activity_id', db.String, db.ForeignKey('activity.id')),
db.Column('event_id', db.Integer(), db.ForeignKey('event.id'))
)
class Event(db.Model, BaseMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String)
class Type(db.Model, BaseMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True)
activities = db.relationship("Activity", backref="type", lazy='dynamic')
class Goal(db.Model, BaseMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
activity_id = db.Column(db.String, db.ForeignKey('activity.id'), primary_key=True)
name = db.Column(db.String())
class DateLocation(db.Model, BaseMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
activity_id = db.Column(db.String, db.ForeignKey('activity.id'), primary_key=True)
start_date = db.Column(db.DateTime)
end_date = db.Column(db.DateTime)
location = db.Column(db.String())
class Activity(db.Model, BaseMixin):
id = db.Column(db.String, primary_key=True)
name = db.Column(db.String())
type_id = db.Column(db.Integer, db.ForeignKey('type.id'))
date_locations = db.relationship("DateLocation", order_by='DateLocation.start_date', cascade="all, delete", backref="activity", lazy='dynamic')
goals = db.relationship("Goal", cascade="all, delete", backref="activity", lazy='dynamic')
events = db.relationship('Event', secondary=EventsInActivities, backref=db.backref('activities', lazy='dynamic'))
答案 0 :(得分:1)
您可以使用EXISTS子查询表达式或semijoins替换过滤器的至少一些连接。这样,您的查询可以避免为单个活动生成多个行。仍然可以加入model.getContent()
,因为这是多对一的关系:
Type
将关键字参数传递给any()
与filter_by()
类似。它也接受复杂的条件表达式和位置参数。
records = m.Activity.query.\
join(m.Activity.type).\
filter(m.Activity.events.any(name=keyword)).\
filter(m.Activity.goals.any(name=...)).\
filter(...).\
order_by(m.Type.name.desc()).\
limit(limit).\
offset((page - 1) * limit)
(或DISTINCT ON)应该也可以正常工作,只要您随后将结果用作子查询,然后对其应用排序和限制:
distinct(m.Activity.id)