2017-07-24 37 views
1

我在將一些SQL翻譯成Django時遇到了麻煩。Django ORM:獲取不同字段的最新記錄

想象一下,我們有一些汽車,每輛汽車都有一個獨特的VIN,我們用其他數據記錄他們在商店的日期。 (請忽略一個可能結構中的數據這樣的原因,它是專門爲這個問題。:-))

class ShopVisit(models.Model): 
    vin = models.CharField(...) 
    date_in_shop = models.DateField(...) 
    mileage = models.DecimalField(...) 
    boolfield = models.BooleanField(...) 

我們希望有一個單一查詢與最近的記錄返回一個QuerySet每個vin和更新它!

special_vins = [...] 

# Doesn't work 
ShopVisit.objects.filter(vin__in=special_vins).annotate(max_date=Max('date_in_shop').filter(date_in_shop=F('max_date')).update(boolfield=True) 

# Distinct doesn't work with update 
ShopVisit.objects.filter(vin__in=special_vins).order_by('vin', '-date_in_shop).distinct('vin').update(boolfield=True) 

是的,我可以迭代查詢集。但這不是非常有效,而且我處理大約2百萬條記錄需要很長時間。可以做到這一點的SQL是(我想!):

SELECT * 
FROM cars 
INNER JOIN (
    SELECT MAX(dateInShop) as maxtime, vin 
    FROM cars 
    GROUP BY vin 
) AS latest_record ON (cars.dateInShop= maxtime) 
    AND (latest_record.vin = cars.vin) 

那麼我怎麼能使這與Django發生?

回答

1

這有點未經測試,並且依賴於Django的1.11子查詢,但也許是這樣的:

latest_visits = Subquery(ShopVisit.objects.filter(id=OuterRef('id')).order_by('-date_in_shop').values('id')[:1]) 

ShopVisit.objects.filter(id__in=latest_visits) 

我有一個類似的模式,所以就去考,但得到了一個錯誤: 「該版本的MySQL還不支持「LIMIT & IN/ALL/ANY/SOME子查詢」

它生成的SQL合理像你想要什麼看,所以我認爲這個想法是合理的。如果你使用PostGres,也許它支持這種類型的子查詢。

這是它產生的SQL(修剪了一下,用假的代替實際的名稱):

SELECT `mymodel_activity`.* FROM `mymodel_activity` WHERE `mymodel_activity`.`id` IN (SELECT U0.`id` FROM `mymodel_activity` U0 WHERE U0.`id` = (`mymodel_activity`.`id`) ORDER BY U0.`date_in_shop` DESC LIMIT 1) 
+0

我要試試這個!我沒有看到1.11的'Subquery'功能 - 它很有前途。 –

+0

我還沒有測試過這樣的代碼 - 我的模型略有不同。儘管我確實使用了這個想法。謝謝! –

0

我想知道你是否自己找到了解決方案。

我可以想出只有原始查詢字符串。 Django Raw SQL query Manual

UPDATE "yourapplabel_shopvisit" 
SET boolfield = True WHERE date_in_shop 
IN (SELECT MAX(date_in_shop) FROM "yourapplabel_shopvisit" GROUP BY vin);