这是一个非常基本的方法。假设您拥有的数据量不是很大,这将正常工作。您可以通过覆盖 get_queryset 函数并仅返回过滤后的方式在视图中使用它。或者,如果您打算在任何地方使用它,也可以将它用作类的静态方法。
values = MyClass.objects.order_by('-created_ts').all()
filtered = []
existing = []
for value in values:
if value.my_integer not in existing:
existing.append(value.my_integer)
filtered.append(value)
由于列表是按最近的第一个排序的,因此它们将被添加到该整数的现有第一个。我用它做了一些基本的测试,但不多,所以可能有一两个缺陷。 用 sqlite 测试。
编辑
这是一个更快的版本。
def iter_tools():
import itertools
qs = MyClass.objects.all()
filtered = []
group_by = itertools.groupby(qs, lambda x: x.my_integer)
for x in group_by:
filtered.append(sorted(x[1], key=lambda x: x.created_ts, reverse=True)[0])
return filtered
本质上,这是从数据库中获取所有对象,按整数对它们进行分组,然后根据时间戳对每个组进行排序,并从每个组中获取第一个。加快速度超出了我的技能,但我相信有一些方法。
这是timeit 与之前在数据库中只有 6 个条目的对比:
In[]: timeit.timeit(manual, number=1500)
Out[]: 0.5577559471130371
In[]: timeit.timeit(iter_tools, number=1500)
Out[]: 0.39012885093688965
-----------------------------------------------
In[]: timeit.timeit(manual, number=5000)
Out[]: 1.770777940750122
In[]: timeit.timeit(iter_tools, number=5000)
Out[]: 1.2411231994628906
编辑 2:
我在数据库中创建了 60000 个对象以使用一些数据进行尝试。我使用 django-fixtureless 生成了数据,因此整数是完全随机的,并且所有整数上的时间戳都是每个对象的新 datetime.now()。
In[]: timeit.timeit(manual, number=1)
Out[]: 11.946185827255249
In[]: timeit.timeit(iter_tools, number=1)
Out[]: 0.7811920642852783
In[]: timeit.timeit(iter_tools, number=100)
Out[]: 77.93837308883667
In[]: MyClass.objects.all().count()
Out[]: 60000
关于数据库的注释: 在上面的示例中,我只是在本地机器上使用 sqlite3。我刚刚设置了一个快速的小型 mysql 服务器作为 vm,并收到了更好的速度结果。
In[16]: MyClass.objects.all().count()
Out[16]: 60000
In[17]: timeit.timeit(iter_tools, number=100)
Out[17]: 49.636733055114746
In[18]: timeit.timeit(iter_tools, number=1)
Out[18]: 0.4923059940338135
无论哪种方式,您都会返回相同的对象。如果性能是一个问题,我建议使用 itertools one 或自定义 sql 查询。