我有一个Parent模型,几个不同类型的项目通过外键用作其父项。我在父模型上也有很多对很多的关系。我正在尝试基于查询多对多模型来获取子模型。
这是父模型
class MediaItem(db.Model):
__tablename__ = "media_item"
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, unique=True)
tags = db.relationship('Tags', secondary=tags_joiner, backref='media_items')
videos = db.relationship('Video', backref='Parent', lazy='dynamic')
audios = db.relationship('Audio', backref='Parent', lazy='dynamic')
pictures = db.relationship('Picture', backref='Parent', lazy='dynamic')
codes = db.relationship('Code', backref='Parent', lazy='dynamic')
与多对多的关系
class Tags(db.Model):
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
tag = db.Column(db.String, unique=True, nullable=False)
tags_joiner = db.Table('tags_joiner',
db.Column('tag_id', db.Integer, db.ForeignKey('tags.id')),
db.Column('mediaitem_id', db.Integer, db.ForeignKey('media_item.id')),
db.PrimaryKeyConstraint('tag_id', 'mediaitem_id'))
最后有一个子模型的例子
class Video(db.Model):
__tablename__ = 'video'
id = db.Column(db.Integer, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey('media_item.id'))
file_name = db.Column(db.String, unique=True)
MediaItem模型中定义的关系证明了其他两种类型的子模型。
我正在寻找通过标签对子模型进行过滤。也就是说,在给定特定标签的情况下,返回与该标签关联的所有子模型。
Video.query.join(media_tags).filter_by(MediaItem.tags.any(Tags.tag.in_(tag)))
返回它不知道如何连接这三个表的信息(找不到连接的FROM子句。尝试连接到,但是得到:找不到'media_item'和'tags'之间的任何外键关系。)
我的解决方法是什么?
版本1:以下查询应返回所需结果:
tag = 'my_filter_tag'
q = (
db.session
.query(Video)
.filter(Video.Parent.has(MediaItem.tags.any(Tags.tag == tag)))
)
它可能不是最理想的,因为它是SQL
由两个嵌套EXISTS
子句产生的,但是绝对是非常易读的sqlalchemy
查询。这是为产生的查询sqlite
:
SELECT video.id AS video_id, video.parent_id AS video_parent_id, video.file_name AS video_file_name
FROM video
WHERE EXISTS (
SELECT 1
FROM media_item
WHERE media_item.id = video.parent_id
AND (
EXISTS (
SELECT 1
FROM tags_joiner, tags
WHERE media_item.id = tags_joiner.mediaitem_id
AND tags.id = tags_joiner.tag_id
AND tags.tag = :tag_1
)
)
)
第2版:更为优化的查询是在上加入media_item
,但仍在exists
标记上执行:
q = (
db.session
.query(Video)
.join(MediaItem, Video.Parent)
.filter(MediaItem.tags.any(Tags.tag == tag))
)
将产生SQL
如下:
SELECT video.id AS video_id, video.parent_id AS video_parent_id, video.file_name AS video_file_name
FROM video
JOIN media_item
ON media_item.id = video.parent_id
WHERE EXISTS (
SELECT 1
FROM tags_joiner, tags
WHERE media_item.id = tags_joiner.mediaitem_id
AND tags.id = tags_joiner.tag_id
AND tags.tag = :tag_1
)
你也可以加入进一步的tags_joiner
和tags
实现的结果。但这消除了一些灵活性:如果您想执行并OR
检查多个标签,结果可能会返回多个Video
行,而保留查询EXISTS
将可以解决这一问题。
请注意,您的代码有一个media_tags
,但不清楚它是什么。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句