2016-04-28 4 views
7

के साथ कई रिश्ते पर फ़िल्टर करता है मेरे पास एक अभिभावक मॉडल है कि एक जोड़े को विभिन्न प्रकार के आइटम विदेशी कुंजी के माध्यम से अपने माता-पिता के रूप में उपयोग करते हैं। मेरे पास मूल मॉडल पर कई रिश्ते हैं। मैं कई मॉडल को पूछताछ के आधार पर बाल मॉडल प्राप्त करने की कोशिश कर रहा हूं।फ्लास्क-स्क्लाक्लेमी पैरेंट मॉडल

यह माता पिता के मॉडल

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' और के बीच किसी भी विदेशी कुंजी रिश्तों नहीं खोजा जा सका 'टैग'।)

इस के लिए मेरा दृष्टिकोण क्या हो सकता है?

उत्तर

5

संस्करण -1: नीचे दिए गए क्वेरी वांछित परिणाम लौटना चाहिए:

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

यह के रूप में यह है उत्पादन दो नेस्टेड EXISTS खंड के साथ SQL, सबसे इष्टतम नहीं हो सकता है, लेकिन निश्चित रूप से यह बहुत है पठनीय 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 है, लेकिन यह स्पष्ट नहीं है कि यह क्या है कि।