我想为
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”,我正在寻找如何让它更流畅的建议。
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()
注意
link_set
允许对与当前监视器相关的链接进行操作。你可以,而且你应该定义一个自定义related_name
(可能是“链接”)
不幸的是,这将只与 Postgres 一起使用,因为
.distinct(*fields)
.