根据外部参数(Django)有效地检索和排序对象列表



在一个 Django 项目中,我有两个元组列表。两个列表中的每个元组都包含一个(user_id, epoch_time_of_joining)对。第一个列表是所有用户的列表。第二个列表是新用户列表,仅包含过去 24 小时内加入的 ID。仅供参考,所有用户的列表也包含新用户,并且两个列表都根据epoch_time_of_joining进行排序(它们实际上是 Redis 排序集)。例如:

all_users = [('16', 1489044722.035625), ('5', 1489561316.306984), ('104', 1498151886.155885), ('3', 1498158931.476488), ('2', 1498158953.978909)]
new_users = [('3', 1498158931.476488), ('2', 1498158953.978909)]

任务是通过 Django ORM 获取所有用户对象的统一对象列表,以便首先按最新用户排序。当结果膨胀超过 100 时,我还必须对结果进行分页。最后,我必须跟踪此统一列表中的最新用户,以便我可以在界面中在他们面前显示"新"标签。

完成上述任务最有效的方法是什么?我无法完全有效地做到这一点。我目前正在尝试:

# COMBINE THE TWO LISTS, DROP TIME, BUT KEEP SORTING INTACT
combined_users = []
for (user_id,time) in all_users:
if (user_id,time) in new_users:
combined_users.append((user_id,1))
else:
combined_users.append((user_id,0))
# GET TUPLE LIST RELEVANT FOR CURRENT PAGE
page_obj = get_page_obj(page_num,combined_users,100)
#RETRIEVE RELEVANT USER OBJECTS
user_objs = User.objects.select_related('userprofile').filter(id__in=[user[0] for user in page_obj.object_list])
# USING NESTED FOR LOOPS TO CREATE FINAL LIST
users = []
for (user_id,is_new) in page_obj.object_list:
for user_obj in user_objs:
if obj.id == user_id:
users.append((obj,is_new))

这有效,但它使用嵌套的 for 循环。用户列表庞大且不断增长,因此我更喜欢以性能更高的方式执行此操作。我想知道我是否可以以某种方式在这里使用字典而不会丢失排序,但就像我之前说的,它不会来找我。

套装会让你的生活更轻松。

existing_users = set(all_users) - set(new_users) #  fast but you lose order
sorted_exist_users = ((i[0], False) for i in sorted(existing_users, key=lambda x: x[1]))
new_users = (i[0], True for i in new_users)
batch = []
is_new_flags = []
for i, idx, is_new in enumerate(itertools.chain(new_users, sorted_exit_users)):
if i % 100:
batch.append(idx)
is_new_flags.append(is_new)
else:
user_objs = User...filter(id_in=batch)
yield zip(user_objs, is_new_flags)
batch, is_new_flags = [], []

我不太确定这是否有效。 选择所有用户对象,对其进行排序,然后选择用户配置文件

user_objs = User.objects.filter(id__in=[user[0] for user in page_obj.object_list]).order_by('some_param')
user_profile_obj = user_objs.select_related('userprofile')

使用in_bulk() 可以帮助将处理从 O(n^2)减少到O(n),因为它返回:

。将每个主键值映射到 具有给定 ID 的对象

请注意它如何更改实现的尾端:

#RETRIEVE RELEVANT USER OBJECTS
user_objs = User.objects.select_related('userprofile').in_bulk([user[0] for user in page_obj.object_list])
# USING ONE FOR LOOP TO CREATE THE FINAL LIST
users = []
for (user_id,is_new) in page_obj.object_list:
users.append((user_objs[user_id],is_new))

此外,将map(itemgetter(0),page_obj.object_list)传递给in_bulk()可能是另一种优化。

最新更新