139 votes

sqlalchemy : comment joindre plusieurs tables par une seule requête ?

J'ai les classes mappées SQLAlchemy suivantes :

 class User(Base):
    __tablename__ = 'users'
    email = Column(String, primary_key=True)
    name = Column(String)

class Document(Base):
    __tablename__ = "documents"
    name = Column(String, primary_key=True)
    author = Column(String, ForeignKey("users.email"))

class DocumentsPermissions(Base):
    __tablename__ = "documents_permissions"
    readAllowed = Column(Boolean)
    writeAllowed = Column(Boolean)

    document = Column(String, ForeignKey("documents.name"))

J'ai besoin d'obtenir une table comme celle-ci pour user.email = "user@email.com" :

 email | name | document_name | document_readAllowed | document_writeAllowed

Comment cela peut-il être fait à l'aide d'une requête de requête pour SQLAlchemy ? Le code ci-dessous ne fonctionne pas pour moi :

 result = session.query(User, Document, DocumentPermission).filter_by(email = "user@email.com").all()

Merci,

141voto

Abdul Kader Points 3590

Essaye ça

 q = Session.query(
         User, Document, DocumentPermissions,
    ).filter(
         User.email == Document.author,
    ).filter(
         Document.name == DocumentPermissions.document,
    ).filter(
        User.email == 'someemail',
    ).all()

65voto

letitbee Points 997

Un bon style serait de configurer des relations et une clé primaire pour les autorisations (en fait, il est généralement bon de configurer des clés primaires entières pour tout, mais peu importe) :

 class User(Base):
    __tablename__ = 'users'
    email = Column(String, primary_key=True)
    name = Column(String)

class Document(Base):
    __tablename__ = "documents"
    name = Column(String, primary_key=True)
    author_email = Column(String, ForeignKey("users.email"))
    author = relation(User, backref='documents')

class DocumentsPermissions(Base):
    __tablename__ = "documents_permissions"
    id = Column(Integer, primary_key=True)
    readAllowed = Column(Boolean)
    writeAllowed = Column(Boolean)
    document_name = Column(String, ForeignKey("documents.name"))
    document = relation(Document, backref = 'permissions')

Ensuite, faites une requête simple avec des jointures :

 query = session.query(User, Document, DocumentsPermissions).join(Document).join(DocumentsPermissions)

12voto

Matt Ian Hong Points 131

En développant la réponse d'Abdul, vous pouvez obtenir un KeyedTuple au lieu d'une collection discrète de lignes en joignant les colonnes :

 q = Session.query(*User.__table__.columns + Document.__table__.columns).\
        select_from(User).\
        join(Document, User.email == Document.author).\
        filter(User.email == 'someemail').all()

3voto

Valery Ramusik Points 1134

Cette fonction produira le tableau requis sous forme de liste de tuples.

 def get_documents_by_user_email(email):
    query = session.query(
       User.email, 
       User.name, 
       Document.name, 
       DocumentsPermissions.readAllowed, 
       DocumentsPermissions.writeAllowed,
    )
    join_query = query.join(Document).join(DocumentsPermissions)

    return join_query.filter(User.email == email).all()

user_docs = get_documents_by_user_email(email)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X