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.