2010-12-12 14 views
67

Ho il seguente:Come convertire un Django QuerySet a un elenco

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

poi:

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) 

ottengo un errore:

'QuerySet' object has no attribute 'remove' 

ho provato tutti i tipi per convertire QuerySet in un set o elenco standard. Niente funziona.

Come è possibile rimuovere un elemento dal QuerySet in modo che non lo elimini dal database e non restituisca un nuovo QuerySet (poiché si trova in un ciclo che non funzionerà)?

risposta

26

Si potrebbe fare questo:

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) 

when QuerySets are evaluated Leggi e notare che non è bene per caricare tutto il risultato nella memoria (ad esempio tramite list()).

Riferimento: itertools.ifilter

Aggiornamento per quanto riguarda il commento:

ci sono vari modi per farlo. One (che non è probabilmente il migliore in termini di memoria e di tempo) è quello di fare esattamente la stessa cosa:

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

ho aggiunto un'altra riga al mio esempio di codice qui sopra, eliminando la stessa voce da exising_question_answers. è possibile usare un ifilter per quello anche in qualche modo? – john

+0

Lo contrassegnerò come corretto perché non sapevo del filtro e mi ero dimenticato di lambda. – john

194

Perché non basta chiamare la lista() sul queryset?

answers_list = list(answers) 

Questo sarà anche valutare l'QuerySet/eseguire la query. È quindi possibile rimuovere/aggiungere da tale elenco.

+3

ho provato quello. non funziona per qualche motivo. – john

+0

quando ho provato questo, ho avuto lo stesso errore. qualcuno può spiegare perché chiamare list() sul queryset lo faccia ancora valutare come un queryset (e quindi non ha un metodo 'remove()')? – john

+0

@john, questo dovrebbe funzionare senza problemi. Puoi pubblicare il codice usando 'list()' che hai provato e non ha funzionato? – Agos

22

E 'un po' difficile da seguire ciò che si sta realmente cercando di fare. La prima affermazione sembra che tu possa recuperare due volte lo stesso oggetto QuerySet of Answer. Prima via answer_set.answers.all() e poi di nuovo tramite .filter(id__in=...). Doppio controllo nel guscio e vedere se questo vi darà l'elenco delle risposte che state cercando:

answers = answer_set.answers.all() 

Una volta che avete ripulito quindi è un po 'più facile per voi (e altri a lavorare sul codice) per leggere potresti voler esaminare .exclude() e __infield lookup.

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

new_answers = answers.exclude(question_answer__in=existing_question_answers) 

La ricerca di cui sopra potrebbe non sincronizzare con le definizioni dei modelli ma sarà probabilmente ottenere abbastanza vicino per finire il lavoro da soli.

Se è ancora necessario ottenere un elenco di valori ID, si desidera giocare con .values_list(). Nel tuo caso probabilmente vorrai aggiungere l'opzione flat = True.

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

Grazie per la risposta. Purtroppo non ho fornito dettagli sufficienti per dimostrare che non posso usare il tuo approccio. – john

+0

La migliore soluzione per il problema descritto. Voglio aggiungere 'new_answers = answers.exclude (question_answer__in = existing_question_answers.values_list ('id', flat = True))' @istruble –

7

Utilizzando l'operatore di sezione con parametro di passaggio che causerebbe la valutazione del set di query e creare un elenco.

list_of_answers = answers[::1] 

o inizialmente che avrebbe potuto fare:

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

Per quanto ne so, django queryset non supporta l'indicizzazione negativa. –

+0

Okay Alexey. Hai ragione qui. Ho aggiornato la risposta. –

2

Perché non basta chiamare .values('reqColumn1','reqColumn2') o .values_list('reqColumn1','reqColumn2') sul set di query?

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

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

O

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

result = [(value1,value2)]

è possibile in grado di fare tutte le operazioni su questo QuerySet, che si fa per la lista.

Problemi correlati