Queryset选择组的最新记录

时间:2018-02-05 14:01:31

标签: python django oracle orm django-queryset

使用Django 1.65 Python 3.4.1 Oracle db

db'Locations'中的表:

  location  | update_time     |  num_01   | num_02 | num_03 |
 -----------+-----------------+-----------+--------+--------
  B         | 06 Feb 18 04:14 |  42       | 43     |   55       
  C         | 22 Feb 17 04:14 |  77       | 99     |   23   
  A         | 05 Feb 18 04:14 |  48       | 43     |   21   
  A         | 01 Feb 18 04:14 |  82       | 83     |   74   

我想为每个位置选择包含最新update_time的行。

上表的结果应为:

  location  | update_time     |  num_01   | num_02 | num_03 |
 -----------+-----------------+-----------+--------+--------
  A         | 05 Feb 18 04:14 |  48       | 43     |   21   
  B         | 06 Feb 18 04:14 |  42       | 43     |   55       
  C         | 22 Feb 17 04:14 |  77       | 99     |   23   

我可以使用查询集返回每个位置的最新更新时间:

latest_updates = Locations.objects.values('location').annotate(max_date=Max('update_time')).order_by('location')

但这只会在我查找整行时返回location和max update_time - num_01,num_02,num_03。

我花了很多时间搜索stackoverflow,但没有什么比这更合适了。 Oracle似乎不支持我可以开始工作的排序和不同选项。

由于某些原因我无法导入Subquery所以这对我来说不是一个选项,而且我仍然坚持使用这个版本的django等,因为它正在起作用。

该表最终会有合理数量的数据,所以我正在寻找一个合理有效的解决方案。

4 个答案:

答案 0 :(得分:1)

对于Django 1.11+,您也可以Subquery,所以这样的方法应该起作用:

from django.db.models import Subquery, OuterRef, F

qs = Location.objects.all()

# make a subquery (filter, order, get 'id')
sq = qs.filter(location=OuterRef('location')).order_by('-update_time').values('id')

# use subquery in your query (via annotation + filter)
qs.annotate(latest=Subquery(sq[:1])).filter(id=F('latest'))

答案 1 :(得分:0)

你应该使用,

latest_updates = Locations.objects.order_by('location', '-update_time').distinct('location')

答案 2 :(得分:0)

您可以尝试以下方法:

Locations.objects.order_by('location', '-update_time').distinct('location')

就我而言,它适用于Django 2.1

答案 3 :(得分:-1)

我在这里找到的最佳解决方案:https://gist.github.com/ryanpitts/1304725

'''
given a Model with:

   category    = models.CharField(max_length=32, choices=CATEGORY_CHOICES)
   pubdate     = models.DateTimeField(default=datetime.now)
   <other fields>

Fetch the item from each category with the latest pubdate.

''' 

model_max_set = Model.objects.values('category').annotate(max_pubdate=Max('pubdate')).order_by()

q_statement = Q()
for pair in model_max_set:
    q_statement |= (Q(category__exact=pair['category']) & Q(pubdate=pair['max_pubdate']))

model_set = Model.objects.filter(q_statement)