2010-08-11 107 views
0

我有一個相當複雜的Django查詢

class Supplier(Model) : 
    pass 

class Customer(Model) : 
    pass 

class Dock(Model) : 
    pass 

class SupplierDockAccess(Model) : 
    supplier = ForeignKey(Supplier) 
    dock = ForeignKey(Dock) 

class SupplierCustomerAccess(Model): 
    supplier = ForeignKey(Supplier) 
    customer = ForeignKey(Customer) 

我有客戶的實例,我想獲得的所有碼頭,客戶可以訪問。客戶可以通過SupplierCustomerAccess訪問供應商,供應商可以通過SupplierDockAccess訪問Docks。我能做到這一點,像這樣:

# get the suppliers the customer has access to 
supplier_customer_accesses = SupplierCustomerAccess.objects.filter(customer=customer) 
suppliers = [s.supplier for s in supplier_customer_accesses] 

# get the docks those suppliers have access to 
supplier_dock_accesses = SupplierDockAccess.objects.filter(supplier__in=suppliers) 
docks = [s.dock for s in supplier_dock_accesses] 

...但隨後產生的碼頭的清單包含重複的,我真的認爲這oughtta有可能做到這一點一氣呵成。任何人都想展示一些強大的django-fu?

回答

2

我能想到的最簡單的方法是將ManyToManyFieldscustom QuerySet/Manager組合起來。

from django.db import models 
class CustomQuerySetManager(models.Manager): 
    """ 
     Class for making QuerySet methods available on result set 
     or through the objects manager. 
    """ 
    def get_query_set(self): 
     return self.model.QuerySet(self.model) 
    def __getattr__(self, attr, *args): 
     try:     
      return getattr(self.__class__, attr, *args) 
     except AttributeError: 
      return getattr(self.get_query_set(), attr, *args) 

class Customer(models.Model): 
    suppliers = models.ManyToManyField(through=SupplierCustomerAccess) 
    objects = CustomQuerySetManager() 
    class QuerySet(QuerySet): 
     def docks(self): 
      return Dock.objects.filter(
        supplierdockaccess__supplier__in=self.suppliers 
       ).distinct() 
    ... 
class Supplier(models.Model): 
    docks = models.ManyToManyField(through=SupplierDockAccess) 
    ... 

你應該可以看到只有一個或兩個命中數據庫(取決於您使用select_related時,你有你的客戶),並且你的代碼是出奇的乾淨:

docks = customer.docks() 
suppliers = customer.suppliers.all() 
... 
+0

這也限制你的JOIN到兩個表,而不是像OP的答案那樣。 – 2010-08-11 16:22:04

2

好吧,我想通了。其中的那些談論它的東西,似乎這樣的伎倆:

docks = Dock.objects.filter(supplierdockaccess__supplier__suppliercustomeraccess__customer=customer).distinct() 

......看着那SQL,它確實做到在一個大的加盟。尼斯。對於回答我自己的問題感到抱歉。

+2

回答自己的問題是非常好。繼續並接受答案,以便後面的人會知道什麼幫助了你。 – 2010-08-11 16:32:21