Flask SQLAlchemy - 根据匹配的多对多对象的数量,按权重/分数对结果进行排序



给定以下模型:

class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(255))
taxonomy = db.Column(db.Unicode(), nullable=False)
created_at = db.Column(db.DateTime, default=db.func.now())
updated_at = db.Column(db.DateTime, default=db.func.now(), onupdate=db.func.now())
__mapper_args__ = {
'polymorphic_identity': 'tag',
'polymorphic_on': taxonomy,
'order_by': name
}

class FooTag(Tag):
id = db.Column(db.Integer, db.ForeignKey('tag.id'), primary_key=True)
__mapper_args__ = {
'polymorphic_identity': 'foo'
}

class BarTag(Tag):
id = db.Column(db.Integer, db.ForeignKey('tag.id'), primary_key=True)
__mapper_args__ = {
'polymorphic_identity': 'bar',
}

class Profile(db.Model):
foo_tags = db.relationship(
"FooTag",
secondary=profiles_tags,
secondaryjoin="and_(Tag.id==profiles_tags.c.tag_id, Tag.taxonomy=='foo')",
uselist=True,
lazy='dynamic'
)
bar_tags = db.relationship(
"BarTag",
secondary=profiles_tags,
secondaryjoin="and_(Tag.id==profiles_tags.c.tag_id, Tag.taxonomy=='bar')",
uselist=True,
lazy='dynamic'
)

无论如何,我可以通过一组Tags过滤Profile对象,然后按匹配Tags的数量对结果进行排序?

foo_tags=[2, 4, 6]
bar_tags=[8, 22, 14] 
results = Profile.join(Profile.foo_tags).filter(FooTag.id.in_(foo_tags)).
join(Profile.bar_tags).filter(BarTag.id.in_(bar_tags)).
paginate(1, 20) 

results的顺序由在每个返回的对象上找到多少个匹配的foo_tags/bar_tags来确定?

这是Python==2.7Flask==0.12.2SQLAlchemy==1.1.11Flask-SQLAlchemy==2.3.2

由于使用的是联接继承,因此FooTagBarTag引用Tag的相同id域,因此无需根据foo_tagsbar_tags分别联接和过滤。相反,你可以加入ProfileTag,或者甚至只是Profileprofiles_tags,过滤,并按键(如Profile.id(分组,如果它有这样的主键(问题中的例子在这方面缺乏(:

results = Profile.query.
join(profiles_tags).
filter(profiles_tags.c.tag_id.in_(foo_tags + bar_tags)).
group_by(Profile.id).
order_by(func.count(), Profile.id)

配置文件 ID 作为仲裁符包含在排序中,以便获得确定性分页。

最新更新