基于时间戳从数据库查询中排除值的有效方法

问题描述 投票:0回答:1

我想为

Link
选择
Monitors
的所有实例,其中
last_change
影响
Shop
。条件:如果有一个
Shop
链接,它不能有一个
Customer
链接,反之亦然。此外,每个
Monitor
只能在每个
theme
出现一次。

class Link(models.Model):
    customers = models.ManyToManyField(Customer, related_name = "%(class)s_name", related_query_name = "customer_link_qs", blank = True)
    shop = models.ForeignKey(Shop, on_delete = models.CASCADE, null = True, blank = True)
    theme = models.PositiveIntegerField("theme", default = 0, choices = [(0, 0), (1, 1)])
    monitor = models.ForeignKey(Monitor, on_delete = models.CASCADE)
    last_change = models.DateTimeField("last change", auto_now = True)

    class Meta:
        unique_together = ["monitor", "theme"]

我的做法:

from collections import defaultdict
monitors_dict = defaultdict(list)
for link in Link.objects.all()
    if link.monitor.store == "mystore":
        monitors_dict[link.monitor].append(link)

last_links = []

for monitor in monitors_dict:
    monitor_links = monitor[1] ## list of all links for a monitor
    last_link = monitor_links.sort(key = lambda x: x.last_change)[-1] ## sort by last_change and take last one
    if last_link.shop != None:
        last_links.append(last_link)

感觉“hacky”,我正在寻找如何让它更流畅的建议。

django django-models django-orm
1个回答
0
投票
monitors = Monitor.objets.filter(store="my_store")
monitors = monitors.annotate(link_id=F("link_set__id"))
monitors = monitors.filter(link_id__isnull=False)
monitors = monitors.alias(link_last_change=F("link_set__last_change"))
monitors = monitors.order_by("id", "-link_last_change").distinct("id")
last_link_ids = Link.objects.filter(id__in=monitors.objects.values_list("link_id", flat=True)) 

如果我正确理解了您的需求,上面的代码应该可以解决问题。
由于

.filter()
,我首先构建了一个“my_store”监视器的结果集,并由于
.annotate()
而将它们与相关链接连接起来。
然后我用
last_change
 检索加入的 
Link
.alias()
列 第五行每个监视器只保留一行,加入的链接是最后一次更改。
然后可以使用链接 ID 来查询您想要的链接实例。

注意

link_set
允许对与当前监视器相关的链接进行操作。你可以,而且你应该定义一个自定义
related_name
(可能是“链接”)

不幸的是,这将只与 Postgres 一起使用,因为

.distinct(*fields)
.
如果您不使用 Postgres,我可以尝试考虑另一种方式。

查询集文档

© www.soinside.com 2019 - 2024. All rights reserved.