2010-12-12 25 views
67

Tengo el siguiente:Cómo convertir un QuerySet Django a una lista

answers = Answer.objects.filter(id__in=[answer.id for answer in answer_set.answers.all()]) 

luego:

for i in range(len(answers)): 
    # iterate through all existing QuestionAnswer objects 
    for existing_question_answer in existing_question_answers: 
     # if an answer is already associated, remove it from the 
     # list of answers to save 
     if answers[i].id == existing_question_answer.answer.id: 
      answers.remove(answers[i])   # doesn't work 
      existing_question_answers.remove(existing_question_answer) 

Me aparece un error:

'QuerySet' object has no attribute 'remove' 

He intentado todo tipo para convertir el QuerySet a un conjunto estándar o lista. Nada funciona.

¿Cómo puedo eliminar un elemento del QuerySet para que no lo elimine de la base de datos y no devuelva un nuevo QuerySet (dado que está en un bucle que no funcionará)?

Respuesta

26

Usted puede hacer esto:

import itertools 

ids = set(existing_answer.answer.id for existing_answer in existing_question_answers) 
answers = itertools.ifilter(lambda x: x.id not in ids, answers) 

Leer when QuerySets are evaluated y tenga en cuenta que no es bueno para cargar todo el resultado en la memoria (por ejemplo a través de list()).

Referencia: itertools.ifilter

actualización en relación con el comentario:

Hay varias maneras de hacer esto. Uno (que probablemente no es el mejor en términos de memoria y tiempo) es hacer exactamente lo mismo:

answer_ids = set(answer.id for answer in answers) 
existing_question_answers = filter(lambda x: x.answer.id not in answers_id, existing_question_answers) 
+0

He agregado una línea más a mi ejemplo de código anterior, eliminando la misma entrada de exising_question_answers. ¿es posible usar un ifilter para eso también de alguna manera? – john

+0

Lo marcaré como correcto porque no sabía sobre el filtro y me había olvidado de las lambdas. – john

194

¿Por qué no simplemente llamar a list() en el queryset?

answers_list = list(answers) 

Esto también evaluará el QuerySet/ejecutará la consulta. Luego puede eliminar/agregar de esa lista.

+3

lo he intentado. no funciona por alguna razón. – john

+0

cuando probé esto, tengo el mismo error. ¿Alguien puede explicar por qué llamar a list() en el queryset todavía lo hace evaluar como un queryset (y por lo tanto no tiene un método 'remove()')? – john

+0

@john, esto debería funcionar sin problemas. ¿Puedes publicar el código usando 'list()' que probaste y no funcionó? – Agos

22

Es un poco difícil de seguir lo que realmente están tratando de hacer. Su primera afirmación parece que puede obtener dos veces el mismo objeto QuerySet de Answer. Primero a través de answer_set.answers.all() y nuevamente a través de .filter(id__in=...). Vuelva a comprobar en la cáscara y ver si esto le dará la lista de respuestas que buscas:

answers = answer_set.answers.all() 

vez que haya que limpiar por lo que es un poco más fácil para usted (y otras personas que trabajan en el código) para leer, puede consultar .exclude() y __infield lookup.

existing_question_answers = QuestionAnswer.objects.filter(...) 

new_answers = answers.exclude(question_answer__in=existing_question_answers) 

La búsqueda anterior podría no sincronizar con sus definiciones de modelos, pero probablemente obtendrá lo suficientemente cerca para terminar el trabajo usted mismo.

Si aún necesita obtener una lista de valores de identificación, entonces usted quiere jugar con .values_list(). En su caso, es probable que desee agregar el plano opcional = Verdadero.

answers.values_list('id', flat=True) 
+0

Gracias por su respuesta. Lamentablemente, no proporcioné suficientes detalles para mostrar que no puedo usar su enfoque. – john

+0

La mejor solución para el problema descrito. Quiero agregar 'new_answers = answers.exclude (question_answer__in = existing_question_answers.values_list ('id', flat = True))' @istruble –

7

Por el uso del operador de la rebanada con parámetro de paso que haría que la evaluación de la queryset y crear una lista.

list_of_answers = answers[::1] 

o un principio que podría haber hecho:

answers = Answer.objects.filter(id__in=[answer.id for answer in 
     answer_set.answers.all()])[::1] 
+0

Por lo que sé, django queryset no admite indexación negativa. –

+0

Bien Alexey. Estás aquí mismo. He actualizado la respuesta. –

2

¿Por qué no llamar .values('reqColumn1','reqColumn2') o .values_list('reqColumn1','reqColumn2') en el conjunto de consultas?

answers_list = models.objects.values('reqColumn1','reqColumn2')

result = [{'reqColumn1':value1,'reqColumn2':value2}]

O

answers_list = models.objects.values_list('reqColumn1','reqColumn2')

result = [(value1,value2)]

Usted puede capaz de hacer toda la operación en esta QuerySet, lo que lo hace para la lista.

Cuestiones relacionadas