2016-04-28 19 views
7

Farklı türdeki öğeler için bir çiftin yabancı anahtar aracılığıyla üst öğeleri olarak kullandığı bir Ana modelim var. Ebeveyn modelinde de çok fazla ilişki var. Çocuk modelini birçok modele göre sorgulamayı temel alıyorum. Flask-SQLAlchemy süzgeci, üst modele çok sayıda ilişki üzerinde süzülüyor

Bu

Son olarak çocuk model fo bir örnek vardır

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) 

bir çift vardır ebeveyn modeli

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

Ve birçok ilişki

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

birçok olduğunu MediaItem modelinde tanımlanan ilişkilerin kanıtladığı diğer çocuk modelleri türleri.

Çocuk modeli üzerinde filtreleme yaparak filtreleme yapmak istiyorum. Yani belirli bir etiket verildiğinde, o etiketle ilişkilendirilmiş tüm alt modellerini döndür. .

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

İade o üç tablo nasıl bağlanacağını bilmiyor ki (katılmadan çalıştı dan katılmak için FROM yan tümcesinde bulabilirsiniz, ancak var olamazdı: 'media_item' ve arasında herhangi bir yabancı anahtar ilişkileri bulamıyor 'etiketler'.)

Buna yaklaşımım ne olabilirdi?

cevap

5

Versiyon-1: Aşağıdaki sorgu istenilen sonucu dönmelidir: Bu iç içe geçmiş iki EXISTS maddeleri ile SQL üretir olduğu gibi

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

O en optimal olmayabilir, ama kesinlikle çok olduğu okunabilir sqlalchemy sorgu. İşte sqlite için üretilen sorgu geçerli:

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

Versiyon-2: Biraz daha optimize sorgu media_item adına katılma olmak, ama sonra yine etiketteki exists gerçekleştirmeniz:

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

SQL aşağıdaki gibi üretecek olan:

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 
    ) 

Yapabilirsin Ayrıca tags_joiner ve tags'a katılın ve sonucu elde edin. Ancak bu biraz esnekliği ortadan kaldırır: Eğer gerçekleştirmek istiyorsanız ve OR birden çok etiketi kontrol ederseniz, sonuç Video satır döndürür, oysa EXISTS sorgusuyla ilgilenirsiniz.


Not kodunuzu bir media_tags var ama ne olduğunu net olmadığını söyledi.