2016-04-28 15 views
7

Tôi có một mô hình Phụ huynh mà một cặp cho các loại mục khác nhau sử dụng làm phụ huynh của chúng thông qua khóa ngoại. Tôi cũng có mối quan hệ nhiều đến nhiều trên mô hình gốc. Tôi đang cố gắng để có được mô hình con dựa trên truy vấn nhiều đến nhiều mô hình.Bộ lọc Flask-SQLAlchemy trên nhiều mối quan hệ với mô hình gốc

Đây là mô hình mẹ

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') 

Và nhiều mối quan hệ

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')) 

Cuối cùng có một ví dụ fo mô hình con

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) 

Có một vài các loại mô hình con khác được chứng minh bằng các mối quan hệ được xác định trong mô hình MediaItem.

Tôi đang tìm cách lọc mô hình con theo thẻ. Đó là để nói rằng cho một thẻ cụ thể, trả về tất cả các mô hình con được liên kết với thẻ đó.

Video.query.join(media_tags).filter_by(MediaItem.tags.any(Tags.tag.in_(tag))) 

Returns rằng nó không biết làm thế nào để kết nối ba bảng, (có thể không tìm thấy một mệnh đề FROM tham gia từ Cố gắng tham gia, nhưng có:. Không thể tìm thấy bất kỳ mối quan hệ khoá ngoại giữa 'media_item' và 'tags'.)

Cách tiếp cận này có thể là gì?

Trả lời

5

Version-1: Các truy vấn dưới đây sẽ trả lại kết quả mong muốn:

tag = 'my_filter_tag' 
q = (
    db.session 
    .query(Video) 
    .filter(Video.Parent.has(MediaItem.tags.any(Tags.tag == tag))) 
) 

Nó có thể không phải là tối ưu nhất, vì nó là sản xuất SQL với hai lồng nhau EXISTS khoản, nhưng chắc chắn nó là rất có thể đọc được sqlalchemy truy vấn. Dưới đây là các truy vấn được sản xuất cho 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 
      ) 
     ) 
    ) 

Version-2: truy vấn Hơi tối ưu hơn sẽ tham gia vào media_item, nhưng sau đó vẫn thực hiện exists trên thẻ:

q = (
    db.session 
    .query(Video) 
    .join(MediaItem, Video.Parent) 
    .filter(MediaItem.tags.any(Tags.tag == tag)) 
) 

sẽ tạo ra SQL như sau:

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 
    ) 

Bạn có thể cũng tham gia thêm vào tags_joinertags và đạt được kết quả. Nhưng điều này sẽ loại bỏ một số tính linh hoạt: nếu bạn muốn thực hiện và OR kiểm tra nhiều thẻ, kết quả có thể trả lại nhiều hàng Video, trong khi vẫn giữ truy vấn với EXISTS sẽ xử lý điều đó.


Lưu ý, rằng mã của bạn có một media_tags, nhưng nó không phải là rõ ràng nó là gì.

Các vấn đề liên quan