У меня есть следующие сопоставленные классы 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"))
Мне нужна такая таблица для user.email = "user@email.com"
:
email | name | document_name | document_readAllowed | document_writeAllowed
Как это можно сделать, используя один запрос для SQLAlchemy? Приведенный ниже код мне не подходит:
result = session.query(User, Document, DocumentPermission).filter_by(email = "user@email.com").all()
Благодарность,
python
sql
join
sqlalchemy
баранкин
источник
источник
result = session.query(User, Document).select_from(join(User, Document)).filter(User.email=='user@email.com').all()
Но я еще не сумел сделать работу аналогичной для трех таблиц (включая DocumentPermissions). Любая идея?Ответы:
Попробуй это
q = Session.query( User, Document, DocumentPermissions, ).filter( User.email == Document.author, ).filter( Document.name == DocumentPermissions.document, ).filter( User.email == 'someemail', ).all()
источник
join
он делает? внутренний, внешний, крест или что?[(<user>, <document>, <documentpermissions>),...]
/select x from a, b ,c
перекрестное соединение. Затем фильтры делают его внутренним соединением..all()
. Чтобыprint Session.query....
точно увидеть, что он делает..filter()
можно получить несколько критериев, если они разделены запятыми. Предпочтительно использовать один.filter()
с разделением запятыми внутри скобок или использовать несколько,.filter()
как в приведенном выше ответе?Хорошим стилем было бы установить некоторые отношения и первичный ключ для разрешений (на самом деле, обычно это хороший стиль для установки целочисленных первичных ключей для всего, но не важно):
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')
Затем выполните простой запрос с объединениями:
query = session.query(User, Document, DocumentsPermissions).join(Document).join(DocumentsPermissions)
источник
query
установлено в последней строке и как получить доступ к объединенным записям в ней?Document
(2-му значению кортежа) в наборе результатов запроса?for (user, doc, perm) in query: print "Document: %s" % doc
Как сказал @letitbee, его лучшая практика - назначать первичные ключи таблицам и правильно определять отношения, чтобы обеспечить правильные запросы ORM. Что, как говорится...
Если вы заинтересованы в написании запроса по строкам:
SELECT user.email, user.name, document.name, documents_permissions.readAllowed, documents_permissions.writeAllowed FROM user, document, documents_permissions WHERE user.email = "user@email.com";
Тогда вы должны пойти на что-то вроде:
session.query( User, Document, DocumentsPermissions ).filter( User.email == Document.author ).filter( Document.name == DocumentsPermissions.document ).filter( User.email == "user@email.com" ).all()
Если вместо этого вы хотите сделать что-то вроде:
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
Затем вы должны сделать что-то вроде:
session.query( User ).join( Document ).join( DocumentsPermissions ).filter( User.email == "user@email.com" ).all()
Одно замечание об этом ...
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
Для получения дополнительной информации посетите docs .
источник
Расширяя ответ Абдула, вы можете получить
KeyedTuple
вместо дискретного набора строк, объединив столбцы:q = Session.query(*User.__table__.columns + Document.__table__.columns).\ select_from(User).\ join(Document, User.email == Document.author).\ filter(User.email == 'someemail').all()
источник
Эта функция создаст требуемую таблицу в виде списка кортежей.
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)
источник