给定以下模型:
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'
)
无论如何,我可以通过一组Tag
s过滤Profile
对象,然后按匹配Tag
s的数量对结果进行排序?
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.7
、Flask==0.12.2
、SQLAlchemy==1.1.11
、Flask-SQLAlchemy==2.3.2
由于使用的是联接继承,因此FooTag
和BarTag
引用Tag
的相同id域,因此无需根据foo_tags
和bar_tags
分别联接和过滤。相反,你可以加入Profile
和Tag
,或者甚至只是Profile
和profiles_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 作为仲裁符包含在排序中,以便获得确定性分页。