Django:更新查询集中对象的顺序属性

发布于 2024-09-05 18:37:13 字数 393 浏览 7 评论 0原文

我的模型上有一个属性,允许用户订购对象。我必须根据列表更新元素的顺序,该列表包含新顺序中对象的 id;现在我正在迭代整个查询集并一个接一个地设置对象。对整个查询集执行相同操作的最简单/最快的方法是什么?

def update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    id_to_order = dict((order[i], i) for i in range(len(order)))
    for x in model.objects.all():
        x.order = id_to_order[x.id]
        x.save()

I'm having a attribute on my model to allow the user to order the objects. I have to update the element's order depending on a list, that contains the object's ids in the new order; right now I'm iterating over the whole queryset and set one objects after the other. What would be the easiest/fastest way to do the same with the whole queryset?

def update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    id_to_order = dict((order[i], i) for i in range(len(order)))
    for x in model.objects.all():
        x.order = id_to_order[x.id]
        x.save()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

贪了杯 2024-09-12 18:37:14

这无法在单个查询集操作中完成。据我所知,它甚至无法通过原始 SQL 的一个查询来完成。因此,您始终需要对每个必须更新的对象进行更新调用。因此,您和科林·安德森的解决方案似乎都非常适合您的描述。

但是,您的用例是什么?整个列表真的每次都会改变吗?在大多数情况下,这似乎不太可能。我可以看到一些不同的方法。

您像您所说的那样保存订单字段,但为订单列表生成差异:def

update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    original_order = model.objects.value_list('id', flat=True).order_by('order')
    order = filter( lambda x: x[1]!=x[2], zip(xrange(len(order)), order, original_order))
    for i in order:
        model.objects.filter(id=i[1]).update(order=i[0])

另一种方法(具体取决于您所做的事情)是如果可能的话进行部分更新(例如使用 AJAX),而不是更新整个重新- 有序集,只需分别更新每个更新。这通常会增加总负载,但随着时间的推移会分散得更多。以将第 5 个元素逐步移动到位置 2 为例,这将引入 3 次交换:(5,4); (4,3); (3,2)。总共需要进行 6 次更新,而采用一次性方法只需 4 次更新。但小规模的行动将随着时间的推移而分散。

This cannot be done in one single queryset operation. As far as I know it can't even be done in one query with raw SQL. So you will always need the update call for each object that has to be updated. So both your and Collin Anderson's solutions seem quite optimal for your description.

However, what's your use case? Is really the whole list going to change every time? In most situations this seems very unlikely. I can see some different approaches.

You save the order field like you say, but you generate a diff for the order list:def

update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    original_order = model.objects.value_list('id', flat=True).order_by('order')
    order = filter( lambda x: x[1]!=x[2], zip(xrange(len(order)), order, original_order))
    for i in order:
        model.objects.filter(id=i[1]).update(order=i[0])

Another approach, depending on what you're making is to do a partial update (e.g. using AJAX) if possible, instead of updating the whole re-ordered set, just update every update separately. This will often increase the total load, but will spread it more over time. Take for example moving the 5th element step-by-step to place 2, this will introduce 3 swaps: (5,4); (4,3); (3,2). Resulting in 6 updates, while with the all-in-one-time approach only 4 will be needed. But the small operations will be spread over time.

无人问我粥可暖 2024-09-12 18:37:14

我不知道是否可以使用一个查询来完成此操作,但在任何情况下这都更有效:

def update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    for id in model.objects.values_list('id', flat=True):
        model.objects.filter(id=id).update(order=order.index(id))

I don't know if it is possible to do this using one query, but this is more efficient in any case:

def update_ordering(model, order):
    """ order is in the form [id,id,id,id] for example: [8,4,5,1,3] """
    for id in model.objects.values_list('id', flat=True):
        model.objects.filter(id=id).update(order=order.index(id))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文