2014-04-25 115 views
0

比方說,我有一個博客頭版有幾個職位,每個有一些標籤(如例如在http://pythonhosted.org/Flask-SQLAlchemy/models.html#many-to-many-relationships但隨着職位的替代頁)。如何使用SQLAlchemy在單個查詢中檢索所有顯示的帖子的所有標籤?SQLAlchemy的許多一對多查詢

我會做它的方式是這樣的(我如果有一個更好的辦法只是好奇):

  • 運行,返回所有相關帖子的網頁查詢。
  • 使用列表理解來獲得在上面的查詢所有職位ID的列表。
  • 運行的是得到其中POST_ID在([帖子ID列表我只是做])的所有標籤

是這樣的方式做到這一點單查詢?

回答

1

這當然是不是這樣做的方式。像sqlalchemy這樣的ORM的目的是將記錄和所有關係/相關記錄表示爲只需處理的對象,而不用考慮基礎的SQL查詢。

你並不需要檢索任何東西。你已經擁有了它。您Post() -objects的tags - 屬性是(像)的Tag() -objects一個list

我不知道燒瓶SQLAlchemy的,但既然你問了我SQLAlchemy隨意張貼,使用從燒瓶例如車型SQLAlchemy例子(包含個體經營):

#!/usr/bin/env python3 
# coding: utf-8 

import sqlalchemy as sqAl 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker, relationship, backref 

engine = sqAl.create_engine('sqlite:///m2m.sqlite') #, echo=True) 
metadata = sqAl.schema.MetaData(bind=engine) 

Base = declarative_base(metadata) 

tags = sqAl.Table('tags', Base.metadata, 
       sqAl.Column('tag_id', sqAl.Integer, sqAl.ForeignKey('tag.id')), 
       sqAl.Column('page_id', sqAl.Integer, sqAl.ForeignKey('page.id')) 
) 

class Page(Base): 
    __tablename__ = 'page' 
    id = sqAl.Column(sqAl.Integer, primary_key=True) 
    content = sqAl.Column(sqAl.String) 
    tags = relationship('Tag', secondary=tags, 
         backref=backref('pages', lazy='dynamic')) 

class Tag(Base): 
    __tablename__ = 'tag' 
    id = sqAl.Column(sqAl.Integer, primary_key=True) 
    label = sqAl.Column(sqAl.String) 

def create_sample_data(sess): 
    tag_strings = ('tag1', 'tag2', 'tag3', 'tag4') 
    page_strings = ('This is page 1', 'This is page 2', 'This is page 3', 'This is page 4') 
    tag_obs, page_obs = [], [] 
    for ts in tag_strings: 
    t = Tag(label=ts) 
    tag_obs.append(t) 
    sess.add(t) 
    for ps in page_strings: 
    p = Page(content=ps) 
    page_obs.append(p) 
    sess.add(p) 

    page_obs[0].tags.append(tag_obs[0]) 
    page_obs[0].tags.append(tag_obs[1]) 
    page_obs[1].tags.append(tag_obs[2]) 
    page_obs[1].tags.append(tag_obs[3]) 
    page_obs[2].tags.append(tag_obs[0]) 
    page_obs[2].tags.append(tag_obs[1]) 
    page_obs[2].tags.append(tag_obs[2]) 
    page_obs[2].tags.append(tag_obs[3]) 

    sess.commit() 

Base.metadata.create_all(engine, checkfirst=True) 

session = sessionmaker(bind=engine)() 
# uncomment the next line and run it once to create some sample data 
# create_sample_data(session) 
pages = session.query(Page).all() 

for p in pages: 
    print("page '{0}', content:'{1}', tags: '{2}'".format(
    p.id, p.content, ", ".join([t.label for t in p.tags]))) 

是的,生活是那麼容易......

+0

感謝您的例子,可惜生活不是那麼容易:)我想要的是,以避免發行爲每個頁面查詢的默認ORM類似的行爲,並就我從運行代碼中看到的情況而言,SQLAlchemy爲每個頁面運行查詢(四次英寸)所有)。在這種情況下,這不是一個大問題,但是如果您有一個包含40個博客帖子或其他項目的網頁,並且對每個帖子運行查詢,那麼效率非常低。所以我正在尋找的是另一種確保我只運行兩個查詢的方法(一個用於獲取帖子,另一個用於獲取相應的標籤) – user3362454

+0

對不起,我沒有幫你解決。你需要做的是爲'relation'和'backref'設置'lazy ='joined''選項。這使它發出一個單一的查詢。每查詢一次,你就可以在不需要標籤的情況下說'session.query(Page).enable_eagerloads(False).all()'。 – TNT

+0

似乎工作。非常感謝你。 – user3362454