Mam następujące zamapowane klasy SQLAlchemy:
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"))
Potrzebuję takiego stolika na user.email = "[email protected]"
:
email | name | document_name | document_readAllowed | document_writeAllowed
Jak można to zrobić za pomocą jednego żądania zapytania dla SQLAlchemy? Poniższy kod nie działa dla mnie:
result = session.query(User, Document, DocumentPermission).filter_by(email = "[email protected]").all()
Dzięki,
python
sql
join
sqlalchemy
barankin
źródło
źródło
result = session.query(User, Document).select_from(join(User, Document)).filter(User.email=='[email protected]').all()
Ale nie udało mi się jeszcze zrobić podobnej pracy dla trzech tabel (aby uwzględnić DocumentPermissions). Dowolny pomysł?Odpowiedzi:
Spróbuj tego
q = Session.query( User, Document, DocumentPermissions, ).filter( User.email == Document.author, ).filter( Document.name == DocumentPermissions.document, ).filter( User.email == 'someemail', ).all()
źródło
join
to robi? wewnętrzna, zewnętrzna, krzyż czy co?[(<user>, <document>, <documentpermissions>),...]
/select x from a, b ,c
który jest złączem krzyżowym. Filtry tworzą następnie sprzężenie wewnętrzne..all()
. Abyprint Session.query....
dokładnie zobaczyć, co robi..filter()
można otrzymać wiele kryteriów, jeśli są oddzielone przecinkami. Czy lepiej jest użyć.filter()
oddzielenia przecinkami w nawiasach, czy użyć wielu,.filter()
jak w powyższej odpowiedzi?Dobrym stylem byłoby ustawienie pewnych relacji i klucza podstawowego dla uprawnień (właściwie zwykle dobrym stylem jest ustawienie całkowitych kluczy głównych dla wszystkiego, ale cokolwiek):
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')
Następnie wykonaj proste zapytanie z łączeniami:
query = session.query(User, Document, DocumentsPermissions).join(Document).join(DocumentsPermissions)
źródło
query
ustawione w ostatnim wierszu i jak uzyskujesz dostęp do połączonych rekordów?Document
(drugiej wartości krotki) w zestawie wyników zapytania?for (user, doc, perm) in query: print "Document: %s" % doc
Jak powiedział @letitbee, najlepszą praktyką jest przypisywanie kluczy podstawowych do tabel i prawidłowe definiowanie relacji, aby umożliwić prawidłowe zapytania ORM. Biorąc to pod uwagę ...
Jeśli chcesz napisać zapytanie w stylu:
SELECT user.email, user.name, document.name, documents_permissions.readAllowed, documents_permissions.writeAllowed FROM user, document, documents_permissions WHERE user.email = "[email protected]";
Następnie powinieneś wybrać coś takiego:
session.query( User, Document, DocumentsPermissions ).filter( User.email == Document.author ).filter( Document.name == DocumentsPermissions.document ).filter( User.email == "[email protected]" ).all()
Jeśli zamiast tego chcesz zrobić coś takiego:
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
Następnie powinieneś zrobić coś w stylu:
session.query( User ).join( Document ).join( DocumentsPermissions ).filter( User.email == "[email protected]" ).all()
Jedna uwaga na ten temat ...
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
Aby uzyskać więcej informacji, odwiedź dokumentację .
źródło
Rozwijając odpowiedź Abdula, możesz uzyskać
KeyedTuple
zamiast dyskretnego zbioru wierszy, łącząc kolumny:q = Session.query(*User.__table__.columns + Document.__table__.columns).\ select_from(User).\ join(Document, User.email == Document.author).\ filter(User.email == 'someemail').all()
źródło
Ta funkcja utworzy wymaganą tabelę jako listę krotek.
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)
źródło