2010-10-24 26 views
3

嗨,夥計們,我有一個模型,其ID不是唯一的。每個模型也有一個日期。我想返回所有結果,但只返回分享ID的每行最近的結果。這個模型看起來是這樣的:查詢所有行並返回每個副本的最新內容

class MyModel(models.Model): 
    my_id = models.PositiveIntegerField() 
    date = models.DateTimeField() 
    title = models.CharField(max_length=36) 


## Add some entries 
m1 = MyModel(my_id=1, date=yesterday, title='stop') 
m1.save() 

m2 = MyModel(my_id=1, date=today, title='go') 
m2.save() 

m3 = MyModel(my_id=2, date=today, title='hello') 
m3.save() 

現在嘗試檢索這些結果:

MyModel.objects.all()... # then limit duplicate my_id's by most recent 

結果應該只有平方米立方米

回答

5

您將無法用ORM做這個,你需要得到所有的記錄,然後丟棄Python中的重複項。

例如:

objs = MyModel.objects.all().order_by("-date") 
seen = set() 
keep = [] 
for o in objs: 
    if o.id not in seen: 
     keep.append(o) 
     seen.add(o.id) 

下面是一些自定義的SQL,可以讓你從數據庫中想要的東西:

select * from mymodel where (id, date) in (select id, max(date) from mymodel group by id) 

你應該能夠適應這種在ORM使用。

+0

只要循環結果,是不是會評估QuerySet並導致所有查找?沒有辦法做到這一點沒有? – Scott 2010-10-24 15:46:12

+0

關係數據庫(以及因此構建的ORM)不適用於行之間的操作(包括比較)。他們的模型基本上是選擇一組行,然後對它們進行排序。我想不出一種方法讓SQL去做你想做的事情。 – 2010-10-24 15:59:34

+0

好的,謝謝你花時間。我想我會以其他方式限制結果(比如只獲得最近的結果)以減輕體重。再次感謝Ned! – Scott 2010-10-24 16:09:23

0

你也應該看看到抽象邏輯入一個經理:

http://docs.djangoproject.com/en/dev/topics/db/managers/

這樣,你可以調用像MyModel.objects.no_dupes(),您會在經理定義no_dupes()並且做內德放在那裏的邏輯。

你的models.py現在看起來是這樣的:

class MyModelManager(models.Manager): 
    def no_dupes: 
     objs = MyModel.objects.all().order_by("-date") 
     seen = set() 
     keep = [] 
     for o in objs: 
      if o.id not in seen: 
       keep.append(o) 
       seen.add(o.id) 
     return keep 

class MyModel(models.Model): 
    my_id = models.PositiveIntegerField() 
    date = models.DateTimeField() 
    title = models.CharField(max_length=36) 
    objects = MyModelManager() 

與上面的代碼中的地方,你可以撥打:MyModel.objects.no_dupes(),這應該給你想要的結果。看起來,你甚至可以覆蓋所有的()函數,以及如果你想的是不是:

http://docs.djangoproject.com/en/1.2/topics/db/managers/#modifying-initial-manager-querysets

我找經理要在情況下更好的解決方案,你將需要不止一個使用此在整個項目中查看,這樣你就不必重寫代碼X次了。

+0

無論我想將過濾器放在自定義管理器中還是視圖中,是否仍然需要獲取所有記錄然後過濾它們?如果可能,我真的想在進行實際的db調用之前進行過濾。這可能嗎? – Scott 2010-10-24 15:50:40

+0

您可以使用管理器修改實際的SQL查詢。看看這裏的例子:http://docs.djangoproject.com/en/dev/topics/db/managers/#adding-extra-manager-methods – 2010-10-24 15:59:02

+0

感謝您對模型管理器的提示,我沒有考慮製作一個定製經理。 – Scott 2010-10-24 16:10:26

-1

正如Ned所說,我不知道用ORM做這件事的方法。但是你也許可以使用db來限制你在python for循環中必須做的工作量。

想法是使用Django的annotate(基本上運行group_by)查找所有具有相同的my_id多行的實例,並按照Ned的建議處理它們。然後對其餘的(沒有重複的),你可以抓住單個行。

from django.db.models import Count, Q 
annotated_qs = MyModel.objects.annotate(num_my_ids=Count('my_id')).order_by('-date') 
dupes = annotated_qs.filter(num_my_ids__gt=1) 
uniques = annotated_qs.filter(num_my_ids__lte=1) 
for dupe in dupes: 
    ... # just keep the most recent, as Ned describes 
keep_ids = [keep.id for keep in keeps] 
latests = MyModel.objects.filter(Q(id__in=keep_ids) | Q(id__in=uniques)) 

如果你只有少量的愚弄,這將意味着你的for循環要短得多,但需額外查詢的費用(以獲得受騙者)。

+0

'Count'不能以這種方式工作。 – 2013-03-01 23:19:05