Python 为个人检索最新对象

Python 为个人检索最新对象,python,django,django-models,django-queryset,Python,Django,Django Models,Django Queryset,所以,我有一个人物模型,然后我有一个模型名。汽车使用的相关部分如下: class Carusage(models.Model): person = models.ForeignKey(Person) start = models.DateTimeField() end = models.DateTimeField(null=True, blank=True) 一个人可以驾驶一辆车,然后系统创建一个新的Carusage实例,并使用start将其保存为当前时间。然后,当该人

所以,我有一个人物模型,然后我有一个模型名。汽车使用的相关部分如下:

class Carusage(models.Model):
    person = models.ForeignKey(Person)
    start = models.DateTimeField()
    end = models.DateTimeField(null=True, blank=True)
一个人可以驾驶一辆车,然后系统创建一个新的Carusage实例,并使用start将其保存为当前时间。然后,当该人员还车时,当前时间将保存到结束

现在,在我的代码中,我有一个人物模型列表,我想为每个人检索汽车使用的最新日期。因此,如果一个人刚刚归还了汽车,我希望最新汽车使用情况的结束字段链接到该人,如果该人仍然拥有汽车,我希望开始字段

我更愿意在一条SQL语句中实现这一点,因为我的人员列表可能会变得非常大(下界~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)
time\u now=datetime.datetime.now()
时间列表=[]
对于p个人列表:
latest=Carusage.objects.filter(person=p).exclude(start\u gte=time\u now).仅限('start','end')。latest('start'))
尝试:

如果以这种方式使用最新的.end异常,则肯定会得到较慢的代码。异常非常昂贵,而且(如果有异常,速度会慢5-10倍)。不要引发和捕获异常,只需使用else:

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

通过这种方式使用异常,您可以保证获得较慢的代码。异常非常昂贵,而且(如果有异常,速度会慢5-10倍)。不要引发和捕获异常,只需使用else:

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

实际上,你有两个独立的结果,你和一个工会在一起

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

  • 尚未归还的车辆

  • 通常,当您有两个单独的规则时,使用两个单独的查询会更快乐

    实际上,您正在按开始(或结束)等于组的最大值的人对车辆使用情况进行分组聚合

    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'))
    

    我想这就是你要找的。

    你实际上有两个独立的结果,你正在和一个联盟一起组合

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

  • 尚未归还的车辆

  • 通常,当您有两个单独的规则时,使用两个单独的查询会更快乐

    实际上,您正在按开始(或结束)等于组的最大值的人对车辆使用情况进行分组聚合

    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'))
    

    我想这就是你要找的。

    我真的没有考虑过这个try-except条款。删除了它,代码运行得更快,但只是稍微快一点。您提出的查询仍然需要访问数据库N次。虽然你的答案使我的代码速度加快了一点,但它仍然不能帮助我尽可能少地访问数据库+但是速度提升1。我真的没有考虑这个try-except条款。删除了它,代码运行得更快,但只是稍微快一点。您提出的查询仍然需要访问数据库N次。虽然你的答案使我的代码速度加快了一点,但它仍然不能帮助我尽可能少地访问数据库+我可以看到其中的逻辑,我认为这在我的sqlite测试数据库中是有效的。但是,当我尝试在使用SQLServer和pyodbc的生产环境中使用它时,我会遇到这样的错误:“文本、ntext和图像数据类型无法进行比较或排序,除非使用IS NULL或LIKE运算符。”更改db模式不是一个选项,因此我想我将在这一个上使用遗留的原始sql代码…:)@Sindri Guðmundsson:“我想我会在这一个上使用遗留的原始sql代码”。糟糕的政策。您的数据模型包含的内容超过了您在问题中所揭示的内容。这意味着您可能必须使用
    aggregate
    而不是
    annotate
    来生成几个选定的字段,以避免使用图像、文本和ntext字段。aggregate只会给我一个日期。从这两条语句中,将annotate替换为aggregate,我只得到两个日期(一个是最近一次归还的汽车,另一个是最近一次未归还的汽车)。为了澄清,我需要每人一个datetime对象。或者你的回答中有什么我不理解的地方吗?@Sindri Guðmundsson:“聚合只能给我一个日期。”“我需要每人一个datetime对象。”我完全不理解你的评论
    aggregate
    将结果集从Person对象更改为聚合值的简单元组。如果需要更多数据,请将其列在
    aggregate
    函数中。请阅读Django文档。请做必要的修改。我无法为您编写应用程序。我可以看到其中的逻辑,我认为这可以在我的sqlite测试数据库上运行。但是,当我尝试在使用SQLServer和pyodbc的生产环境中使用它时,我会遇到这样的错误:“文本、ntext和图像数据类型无法进行比较或排序,除非使用IS NULL或LIKE运算符。”更改db模式不是一个选项,因此我想我将在这一个上使用遗留的原始sql代码…:)@Sindri Guðmundsson:“我想我会在这一个上使用遗留的原始sql代码”。糟糕的政策。您的数据模型包含的内容超过了您在问题中所揭示的内容。这意味着您可能必须使用
    aggregate
    而不是
    annotate
    来生成几个选定的字段,以避免使用图像、文本和ntext字段。aggregate只会给我一个日期。从这两条语句中,替换注释