一个相当复杂的django查询

时间:2010-08-11 15:22:51

标签: django django-models

我有

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)

我有一个Customer实例,我想获得客户可以访问的所有Docks。客户可以通过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]

...但是生成的码头列表包含重复项,我真的认为它应该可以一次完成。有人觉得要展示一些强大的django-fu?

2 个答案:

答案 0 :(得分:2)

好吧,我明白了。谈论它的其中一个似乎就是诀窍:

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

...并且看着sql,它确实在一个大的连接中做到了。尼斯。很抱歉回答我自己的问题。

答案 1 :(得分: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()
...