检索人的最新对象

时间:2011-05-25 12:32:12

标签: python django django-models django-queryset

所以,我有一个Person模型,然后我有一个模型名称Carusage。 Carusage的相关部分是:

class Carusage(models.Model):
    person = models.ForeignKey(Person)
    start = models.DateTimeField()
    end = models.DateTimeField(null=True, blank=True)

一个人可以开车,然后系统会创建一个新的Carusage实例,并以start作为当前时间进行保存。然后当Person返回汽车时,当前时间将保存到结束。

现在,在我的代码中,我有一个Person模型列表,我想在每个人的Carusage中检索最新的日期。因此,如果一个人刚刚归还了这辆车,我会希望最新Carusage的终点字段与该人相关联,如果该人仍然拥有该车,我会想要一个起始字段。

我希望在一个SQL语句中执行此操作,因为我的Person-list可能会变得非常大(下限~10,上限~10,000)。我试过这样的事情:

Carusage.objects.filter(person__in(person_list)).exclude(start__gte(time_now))

然后考虑注释,但想不出我将如何继续。

所以目前我这样做:

time_now = datetime.datetime.now()
time_list = []
for p in person_list:
    latest = Carusage.objects.filter(person=p).exclude(start__gte=time_now).only('start', 'end').latest('start')
    try:
        if latest.end<time_now:
            time=latest.end
        else:
            raise
    except:
        time=latest.start
    time_list.append(time)

显然我的代码运行缓慢(500人列表大约5秒)。运行这个/这些查询的“django-way”是什么? 我想要实现的两件事:只为Carusage打了一次数据库(至少不是len(person_list)次),只从数据库中获取相关时间(只需要最新的时间......)。 有没有办法实现这个目标?

2 个答案:

答案 0 :(得分:2)

通过这种方式使用异常,您可以保证获得慢速代码。例外是非常昂贵的potentially slow down your code a lot(例外情况下慢了5-10倍)。不要提出和捕获异常,只需使用else:

if latest.end<time_now:
   time=latest.end
else:
   time=latest.start

你也可以简单地使用Django的order_by过滤器吗?例如,要通过起始值获取给定人员订单的所有“Carusages”,请调用:

Carusage.objects.filter(person=p).order_by('-start').all()

答案 1 :(得分:2)

你实际上有两个单独的结果,你正在与一个联盟。

  1. 汽车归来了。开始和结束时间。每人(可能)有很多车,你只想要其中一辆车。即使在纯SQL中,这也是一个相当复杂的查询,需要HAVING子句并导致(可能)性能降低。

  2. 汽车尚未归还。

  3. 通常情况下,当您有两个单独的规则时,您会对两个单独的查询感到满意。

    您实际上正在对按人员分组的CarUsage进行聚合,其开头(或结尾)等于该组的最大值。

    returned = Person.objects.filter( carusage__end__isnull=True ).annotate(Max('carusage__start'))
    not_returned = Person.objects.filter( carusage__end__isnull=False ).annotate(Max('carusage__end'))
    

    我认为这就是你要找的东西。