【问题标题】:a fairly complex django query一个相当复杂的 Django 查询
【发布时间】:2011-03-28 11:05:01
【问题描述】:

我有

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)

我有一个客户实例,我想获取客户有权访问的所有 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 吗?

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    我能想到的最简单的方法是结合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()
    ...
    

    【讨论】:

    • 这也将您的 JOIN 限制为两个表,而不是像 OP 的答案那样四个表。
    【解决方案2】:

    好吧,我想通了。谈论它似乎可以解决问题的事情之一:

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

    ...看看 sql,它确实是在一个大连接中完成的。好的。抱歉回答我自己的问题。

    【讨论】:

    • 回答您自己的问题非常好。来吧,接受答案,这样后面的人就会知道是什么帮助了你。
    猜你喜欢
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 2012-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多