2015-10-08 90 views
2

我需要編寫一個複雜的查詢,它從一堆表中檢索大量數據。基本上,我需要找到模型帶連接的Django查詢

  • 客戶
  • 付款
  • 發票

其中的關係以特定的方式相交的所有實例。在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

一些數據庫專家說,如果您的查詢跨越兩個以上的表,那麼您應該使用SQL而不是使用ORM。就我個人而言,我從來沒有基準測試過這兩個選項,但你可以嘗試這樣做。 – elynch

回答

1

在閱讀了不同的解決方案後,我決定在我的Django模型上使用SqlAlchemy。有些人嘗試用SqlAlchemy完全替代Django ORM,但這幾乎完全違背了使用Django的目的,因爲大多數框架都依賴於ORM。

相反,我使用SqlAlchemy來查詢由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相同的連接,這意味着如果我在同一個上下文中使用兩種方法,事物的視圖可能不會一致。這對我來說不會有問題,因爲我只是想從數據庫中讀取一堆數據。

+0

aldjemy使這種方法更好:https://pypi.python.org/pypi/aldjemy – spookylukey

+0

不知道我是否信任Aldjemy。它基本上沒有記錄(我認爲它很簡單,沒有太多可以說),並且它似乎與python3中的模糊錯誤消息打破。雖然謝謝:) – Eldamir

-1
for customer in customers: 
    for payment in customer.payments: 
     for invoice in payment.invoices: 
      # Do stuff 

SQLAlchemy版本有什麼不同?

在我看來,這是好得多,因爲你走的是真實的結構,而不是桌子。你可以(你應該)有單獨的子程序處理每個級別。

+0

在客戶查詢集上使用'prefetch_related'之後,你會做什麼不會多次觸及數據庫,對嗎?如果我不希望所有客戶付款,該怎麼辦?我是否仍然可以過濾它們而不碰到數據庫? – Eldamir

+0

Yeap,看看[那裏](https://docs.djangoproject.com/en/1.7/ref/models/queries/#django.db.models.Prefetch)。 –

+0

嗯...好吧,所以有可能...我的代碼會因爲我正在處理的特定用例而變得麻煩。我有很多應用的過濾器。本來很高興將它們添加到單個查詢中。感謝您的幫助 – Eldamir