2010-06-15 17 views
5

Estoy teniendo un atributo en mi modelo para permitir que el usuario ordene los objetos. Tengo que actualizar el orden del elemento según una lista que contenga los identificadores del objeto en el nuevo orden; ahora estoy iterando sobre todo el conjunto de preguntas y establezco un objeto después del otro. ¿Cuál sería la forma más fácil/rápida de hacer lo mismo con todo el conjunto de preguntas?Django: atributo de orden de actualización para objetos en un conjunto de consulta

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

Respuesta

4

Esto no se puede hacer en una sola operación queryset. Hasta donde yo sé, ni siquiera se puede hacer en una consulta con SQL sin formato. Por lo tanto, siempre necesitará la llamada de actualización para cada objeto que deba actualizarse. Entonces, tanto su solución como la de Collin Anderson parecen ser óptimas para su descripción.

Sin embargo, ¿cuál es su caso de uso? ¿Realmente toda la lista va a cambiar todo el tiempo? En la mayoría de las situaciones esto parece muy poco probable. Puedo ver algunos enfoques diferentes.

Se ahorra el campo orden como usted dice, pero se genera un diff de la lista de pedidos: 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]) 

Otro enfoque, dependiendo de lo que está haciendo es hacer una actualización parcial (por ejemplo, utilizando AJAX) si es posible, en lugar de actualizar todo el conjunto reordenado, simplemente actualice cada actualización por separado. Esto a menudo aumentará la carga total, pero se extenderá más con el tiempo. Tomemos, por ejemplo, mover el quinto elemento paso a paso al lugar 2, esto introducirá 3 intercambios: (5,4); (4,3); (3,2). Resultando en 6 actualizaciones, mientras que con el enfoque "todo en uno" solo se necesitarán 4. Pero las operaciones pequeñas se extenderán a lo largo del tiempo.

1

No sé si es posible hacerlo mediante una consulta, pero esto es más eficiente en todo caso:

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

Supongo que solo ahorra al golpear el db una vez para obtener todos los elementos (todos los elementos tienen que actualizarse, por lo que su solución también itera sobre todos ellos). –

Cuestiones relacionadas