2010-07-17 62 views
4

我有以下的車型領域查找:鏈過濾器和排除上的Django模型與跨越的關係

class Order_type(models.Model): 
    description = models.CharField() 

class Order(models.Model): 
    type= models.ForeignKey(Order_type) 
    order_date = models.DateField(default=datetime.date.today) 
    status = models.CharField() 
    processed_time= models.TimeField() 

我想有符合此條件的訂單訂單類型的列表:今天order_date < =(和processed_time是空的,status不爲空)

我想:

qs = Order_type.objects.filter(order__order_date__lte=datetime.date.today(),\ 
    order__processed_time__isnull=True).exclude(order__status='') 

這適用於訂單的原始列表:

orders_qs = Order.objects.filter(order_date__lte=datetime.date.today(), processed_time__isnull=True) 
orders_qs = orders_qs.exclude(status='') 

qs是不正確的查詢集。我認爲它實際上返回一個更窄的過濾器(因爲沒有記錄存在),但我不知道是什麼。根據這個(django reference),因爲我引用了一個相關的模型,我認爲排除對原始查詢集(不是來自過濾器的那個)起作用,但我不完全知道如何。

OK,我只是想到了這一點,我認爲作品,但感覺馬虎(有沒有更好的辦法?):

qs = Order_type.objects.filter(order__id__in=[o.id for o in orders_qs]) 

回答

6

發生了什麼事是排除()查詢是搞亂的東西彌補您。基本上,它排除了至少有一個訂單沒有狀態的任何訂單類型,這幾乎不是你想要發生的。

你的情況最簡單的解決方案是在你的filter()參數中使用order__status__gt=''。但是,您還需要在查詢的末尾附加distinct(),因爲否則,如果具有多個與查詢匹配的Order,則您將獲得具有相同Order_type的多個實例的QuerySet。這應該工作:

qs = Order_type.objects.filter(
    order__order_date__lte=datetime.date.today(), 
    order__processed_time__isnull=True, 
    order__status__gt='').distinct() 

在一個側面說明,在QS查詢你給的問題的最後,你不必說了order__id__in=[o.id for o in orders_qs],你可以簡單地使用order__in=orders_qs(你仍然還需要distinct() )。因此,這也將工作:

qs = Order_type.objects.filter(order__in=Order.objects.filter(
    order_date__lte=datetime.date.today(), 
    processed_time__isnull=True).exclude(status='')).distinct() 

附錄(編輯):

下面是實際的SQL,對於上述查詢集Django的問題:

SELECT DISTINCT "testapp_order_type"."id", "testapp_order_type"."description" 
    FROM "testapp_order_type" 
    LEFT OUTER JOIN "testapp_order" 
    ON ("testapp_order_type"."id" = "testapp_order"."type_id") 
     WHERE ("testapp_order"."order_date" <= E'2010-07-18' 
     AND "testapp_order"."processed_time" IS NULL 
     AND "testapp_order"."status" > E''); 

SELECT DISTINCT "testapp_order_type"."id", "testapp_order_type"."description" 
    FROM "testapp_order_type" 
    INNER JOIN "testapp_order" 
    ON ("testapp_order_type"."id" = "testapp_order"."type_id") 
     WHERE "testapp_order"."id" IN 
      (SELECT U0."id" FROM "testapp_order" U0 
       WHERE (U0."order_date" <= E'2010-07-18' 
       AND U0."processed_time" IS NULL 
       AND NOT (U0."status" = E''))); 

EXPLAIN顯示,第二個查詢(稍微昂貴一些)(28.99美元,而非常小的數據集則爲28.64美元)。

+0

感謝您的建議和非常詳細的分析。很有用 – rsp 2010-08-09 11:17:55