Django:更新查询集中对象的订单属性

时间:2010-06-15 18:58:14

标签: python django performance list django-queryset

我的模型上有一个属性,允许用户订购对象。我必须根据列表更新元素的顺序,列表包含新顺序中对象的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()

2 个答案:

答案 0 :(得分:5)

这不能在一个查询集操作中完成。据我所知,甚至不能在一个带有原始SQL的查询中完成。因此,您将始终需要对每个必须更新的对象进行更新调用。因此,你的和Collin Anderson的解决方案似乎都非常适合你的描述。

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

您可以按照说明保存订单字段,但为订单列表生成差异: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次更新。但小型业务将随着时间的推移而扩散。

答案 1 :(得分:1)

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

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))