我需要编写一个复杂的查询,它从一堆表中检索大量数据。基本上我需要找到模型的所有实例
其中关系以特定方式相交。在SqlAlchemy中,我可以做类似
的操作for c, p, i in session.query(Customer, Payment, Invoice).\
filter(User.id==Payment.customer_id).\
filter(Invoice.id==Payment.invoice_id).\
filter(Payment.date==...).\
filter(Customer.some_property==...)
all():
# Do stuff ...
这将允许我设置几个约束并一次检索所有约束。在Django中,我目前做的事情就像
一样愚蠢customers = Customer.objects.filter(...)
payments = Payment.objects.filter(customer=customer)
invoices = Invoice.objects.filter(customer=customer, payment_set=payments)
现在,我们已经有三个不同的查询(省略了一些细节以保持简单)。我能把它减少到一个吗?好吧,我本可以做点像
customers = Customer.objects.filter(...).prefetch_related(
'payments', 'payments__invoices'
)
但是现在我必须遍历一个疯狂的数据树,而不是像SqlAlchemy一样整齐排列。有没有什么方法Django可以做这样的事情?或者我是否必须直接使用自定义SQL?
答案 0 :(得分:1)
在阅读了不同的解决方案后,我决定在我的Django模型之上使用SqlAlchemy。有些人试图用SqlAlchemy完全取代Django ORM,但这几乎完全违背了使用Django的目的,因为大部分框架都依赖于ORM。
相反,我使用SqlAlchemy simple来查询Django ORM定义的表。我遵循类似于此的配方
# Setup sqlalchemy bindings
import sqlalchemy as s
from sqlalchemy.orm import sessionmaker
engine = s.create_engine('postgresql://<user>:<password>@<host>:<port>/<db_name>')
# Automatically read the database tables and create metadata
meta = s.MetaData()
meta.reflect(bind=engine)
Session = sessionmaker(bind=engine)
# Create a session, which can query the tables
session = Session()
# Build table instances without hardcoding tablenames
s_payment = meta.tables[models.Payment()._meta.db_table]
s_allocation = meta.tables[models.Allocation()._meta.db_table]
s_customer = meta.tables[models.Customer()._meta.db_table]
s_invoice = meta.tables[models.Invoice()._meta.db_table]
report = session.query(s_payment.c.amount, ...).all()
此配方有一些改进空间,例如:创建Django模型的空实例以找到它们的表名称并不是很优雅,但是,通过几行代码,我可以获得SqlAlchemy的完全灵活性而不会影响Django ORM层。这意味着两者可以幸福地生活在一起。
有一点需要注意,SqlAlchemy不会使用与Django ORM相同的连接,这意味着如果我在同一个上下文中使用这两种方法,那么事物视图可能看起来不一致。这对我来说不会成为问题,因为我只是想从数据库中读取一堆数据。
答案 1 :(得分:-1)
for customer in customers:
for payment in customer.payments:
for invoice in payment.invoices:
# Do stuff
与SQLAlchemy
版本有什么不同?
在我看来,这是更好的,因为你走的是一个真实的结构,而不是一张桌子。你可以(而且你应该)有单独的子程序来处理每个级别。