web-dev-qa-db-fra.com

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

J'ai les classes mappées SQLAlchemy suivantes:

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

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

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

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

J'ai besoin d'une table comme celle-ci pour user.email = "[email protected]":

email | name | document_name | document_readAllowed | document_writeAllowed

Comment cela peut-il être fait en utilisant 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 = "[email protected]").all()

Merci,

77
barankin

Essaye ça

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

Un bon style serait d’établir des relations et une clé primaire pour les permissions (en fait, c’est un bon style pour installer entier clés primaires pour tout, mais peu importe):

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

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

class DocumentsPermissions(Base):
    __table= "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)
43
letitbee

Comme @letitbee l'a dit, il est préférable d'affecter des clés primaires aux tables et de définir correctement les relations pour permettre une interrogation ORM correcte. Cela étant dit...

Si vous souhaitez rédiger une requête dans le sens suivant:

SELECT
    user.email,
    user.name,
    document.name,
    documents_permissions.readAllowed,
    documents_permissions.writeAllowed
FROM
    user, document, documents_permissions
WHERE
    user.email = "[email protected]";

Ensuite, vous devriez aller pour quelque chose comme:

session.query(
    User, 
    Document, 
    DocumentsPermissions
).filter(
    User.email == Document.author
).filter(
    Document.name == DocumentsPermissions.document
).filter(
    User.email == "[email protected]"
).all()

Si au lieu de cela, vous voulez faire quelque chose comme:

SELECT 'all the columns'
FROM user
JOIN document ON document.author_id = user.id AND document.author == User.email
JOIN document_permissions ON document_permissions.document_id = document.id AND document_permissions.document = document.name

Ensuite, vous devriez faire quelque chose comme:

session.query(
    User
).join(
    Document
).join(
    DocumentsPermissions
).filter(
    User.email == "[email protected]"
).all()

Une note à ce sujet ...

query.join(Address, User.id==Address.user_id) # explicit condition
query.join(User.addresses)                    # specify relationship from left to right
query.join(Address, User.addresses)           # same, with explicit target
query.join('addresses')                       # same, using a string

Pour plus d'informations, visitez le site docs .

23
Ullauri

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()
4
Matt Ian Hong

Cette fonction produira la table requise sous forme de liste de n-uplets.

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)
1
Valery Ramusik