嘿伙计们,我有一个不具有唯一身份的模特。每个型号也有一个日期。我想返回所有结果,但只返回共享ID的每一行的最新结果。该模型看起来像这样:
class MyModel(models.Model):
my_id = models.PositiveIntegerField()
date = models.DateTimeField()
title = models.CharField(max_length=36)
## Add some entries
m1 = MyModel(my_id=1, date=yesterday, title='stop')
m1.save()
m2 = MyModel(my_id=1, date=today, title='go')
m2.save()
m3 = MyModel(my_id=2, date=today, title='hello')
m3.save()
现在尝试检索这些结果:
MyModel.objects.all()... # then limit duplicate my_id's by most recent
结果应仅 m2 和 m3
答案 0 :(得分:6)
您将无法仅使用ORM执行此操作,您需要获取所有记录,然后在Python中丢弃重复项。
例如:
objs = MyModel.objects.all().order_by("-date")
seen = set()
keep = []
for o in objs:
if o.id not in seen:
keep.append(o)
seen.add(o.id)
这是一些可以从数据库中获得所需内容的自定义SQL:
select * from mymodel where (id, date) in (select id, max(date) from mymodel group by id)
您应该能够将其调整为在ORM中使用。
答案 1 :(得分:0)
您还应该考虑将上述逻辑抽象为经理:
http://docs.djangoproject.com/en/dev/topics/db/managers/
这样你可以调用类似MyModel.objects.no_dupes()的东西,在那里你可以在一个管理器中定义no_dupes()并在那里布置逻辑Ned。
您的models.py现在看起来像这样:
class MyModelManager(models.Manager):
def no_dupes:
objs = MyModel.objects.all().order_by("-date")
seen = set()
keep = []
for o in objs:
if o.id not in seen:
keep.append(o)
seen.add(o.id)
return keep
class MyModel(models.Model):
my_id = models.PositiveIntegerField()
date = models.DateTimeField()
title = models.CharField(max_length=36)
objects = MyModelManager()
使用上面的代码,你可以调用:MyModel.objects.no_dupes(),这应该给你想要的结果。看起来你甚至可以覆盖all()函数,如果你想要的话:
http://docs.djangoproject.com/en/1.2/topics/db/managers/#modifying-initial-manager-querysets
我发现经理是一个更好的解决方案,以防你需要在整个项目的多个视图中使用它,这样你就不必重复代码X次了。
答案 2 :(得分:-1)
正如Ned所说,我不知道如何用ORM做到这一点。但是您可以使用db来限制在python中for循环中必须完成的工作量。
这个想法是使用Django的annotate
(基本上运行group_by
)来查找具有多个具有相同my_id
的行的所有实例,并将其处理为Ned建议。然后对于余数(没有重复),你可以抓住各行。
from django.db.models import Count, Q
annotated_qs = MyModel.objects.annotate(num_my_ids=Count('my_id')).order_by('-date')
dupes = annotated_qs.filter(num_my_ids__gt=1)
uniques = annotated_qs.filter(num_my_ids__lte=1)
for dupe in dupes:
... # just keep the most recent, as Ned describes
keep_ids = [keep.id for keep in keeps]
latests = MyModel.objects.filter(Q(id__in=keep_ids) | Q(id__in=uniques))
如果你只有少量的欺骗,这将意味着你的for循环要短得多,代价是额外的查询(以获得欺骗)。