So konvertieren Sie ein Django QuerySet in eine Liste

120

Ich habe folgendes:

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

dann später:

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)

Ich erhalte eine Fehlermeldung:

'QuerySet' object has no attribute 'remove'

Ich habe alle möglichen Versuche unternommen, das QuerySet in einen Standardsatz oder eine Standardliste zu konvertieren. Nichts funktioniert.

Wie kann ich ein Element aus dem QuerySet entfernen, damit es nicht aus der Datenbank gelöscht wird und kein neues QuerySet zurückgibt (da es sich in einer Schleife befindet, die nicht funktioniert)?

John
quelle

Antworten:

42

Sie könnten dies tun:

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)

Lesen Sie, wann QuerySets ausgewertet werden, und beachten Sie, dass es nicht sinnvoll ist, das gesamte Ergebnis in den Speicher zu laden (z list(). B. über ).

Referenz: itertools.ifilter

Update bezüglich des Kommentars:

Es gibt verschiedene Möglichkeiten, dies zu tun. Eine (die in Bezug auf Speicher und Zeit wahrscheinlich nicht die beste ist) besteht darin, genau dasselbe zu tun:

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)
Felix Kling
quelle
Ich habe meinem obigen Codebeispiel eine weitere Zeile hinzugefügt und denselben Eintrag aus exising_question_answers gelöscht. ist es auch möglich, dafür einen ifilter zu verwenden?
John
Ich werde dies als richtig markieren, da ich nichts über Filter wusste und Lambdas vergessen hatte.
John
314

Warum nicht einfach anrufen list()auf das Queryset?

answers_list = list(answers)

Dadurch wird auch QuerySetdie Abfrage ausgewertet . Sie können diese Liste dann entfernen / hinzufügen.

Zeppomedio
quelle
9
Sei vorsichtig damit. Wenn Sie dies in eine Liste umwandeln, wird das eindeutige Flag möglicherweise ignoriert.
Rh0dium
Ich kann es unabhängig machen, aber ich kann es in Queryset in Django-Form machen. Irgendeine Idee warum?
ismailsunni
Wenn ja, dann werfen Sie zu setund dann zurück list, um die einzigartigen zu erhalten.
Radtek
36

Es ist ein wenig schwierig zu verfolgen, was Sie wirklich versuchen zu tun. Ihre erste Anweisung sieht so aus, als würden Sie möglicherweise zweimal genau dasselbe QuerySet of Answer-Objekt abrufen. Erst über answer_set.answers.all()und dann wieder über .filter(id__in=...). Überprüfen Sie die Shell noch einmal und prüfen Sie, ob Sie dadurch die Liste der Antworten erhalten, nach denen Sie suchen:

answers = answer_set.answers.all()

Sobald Sie, dass aufgeräumt , so dass es ein wenig einfacher ist für Sie (und andere auf dem Code arbeiten) möchten Sie vielleicht prüfen, lesen .exclude () und die __in Feld Lookup .

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

new_answers = answers.exclude(question_answer__in=existing_question_answers)

Die obige Suche wird möglicherweise nicht mit Ihren Modelldefinitionen synchronisiert, bringt Sie jedoch wahrscheinlich nahe genug heran, um den Auftrag selbst abzuschließen.

Wenn Sie immer noch eine Liste mit ID-Werten benötigen, möchten Sie mit .values_list () spielen . In Ihrem Fall möchten Sie wahrscheinlich die optionale Ebene = True hinzufügen.

answers.values_list('id', flat=True)
istruble
quelle
Danke für deine Antwort. Leider habe ich nicht genügend Details angegeben, um zu zeigen, dass ich Ihren Ansatz nicht verwenden kann.
John
1
Beste Lösung für das beschriebene Problem. Ich möchte hinzufügen , new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@istruble
aquaman
Der sauberste Weg ist flat=TrueDanke !!!!!!!
Cho
18

Durch die Verwendung eines Slice-Operators mit Schrittparameter, der eine Auswertung des Abfragesatzes bewirken und eine Liste erstellen würde.

list_of_answers = answers[::1]

oder anfangs hättest du tun können:

answers = Answer.objects.filter(id__in=[answer.id for answer in
        answer_set.answers.all()])[::1]
Ankit Singh
quelle
Soweit ich weiß, unterstützt Django Queryset keine negative Indizierung.
Alexey Sidash
Okay Alexey. Sie sind hier richtig. Ich habe die Antwort aktualisiert.
Ankit Singh
15

Sie können direkt mit dem listSchlüsselwort konvertieren . Beispielsweise:

obj=emp.objects.all()
list1=list(obj)

Mit dem obigen Code können Sie ein Abfragesatzergebnis direkt in ein konvertieren list.

Hier listist das Schlüsselwort und objdas Ergebnis des Abfragesatzes und list1die Variable in der Variablen, in der das konvertierte Ergebnis gespeichert wird list.

Patel Shahrukh
quelle
1
Aber wenn Sie dies tun, funktioniert es nicht: Das list1 = list(emp.objects.all())scheint nicht intuitiv zu sein.
Geoidesic
4

Warum nicht einfach anrufen .values('reqColumn1','reqColumn2')oder .values_list('reqColumn1','reqColumn2')auf dem Queryset?

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

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

ODER

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

result = [(value1,value2)]

Sie können alle Vorgänge für dieses QuerySet ausführen, die Sie für die Liste ausführen.

Piyush S. Wanare
quelle
1
def querySet_to_list(qs):
    """
    this will return python list<dict>
    """
    return [dict(q) for q in qs]

def get_answer_by_something(request):
    ss = Answer.objects.filter(something).values()
    querySet_to_list(ss) # python list return.(json-able)

Dieser Code konvertiert Django-Abfrageset in Python-Liste

EunSeong Lee
quelle
0

Versuchen Sie dies values_list('column_name', flat=True).

answers = Answer.objects.filter(id__in=[answer.id for answer in answer_set.answers.all()]).values_list('column_name', flat=True)

Sie erhalten eine Liste mit den angegebenen Spaltenwerten

Sakeer
quelle
0

Stattdessen remove()können Sie die exclude()Funktion verwenden, um ein Objekt aus dem Abfragesatz zu entfernen. Die Syntax ist ähnlich wiefilter()

zB : -

qs = qs.exclude(id= 1)

im obigen Code werden alle Objekte mit der ID '1' aus qs entfernt.

zusätzliche Infos : -

filter()Dient zum Auswählen bestimmter Objekte, exclude()wird jedoch zum Entfernen verwendet

Muhammed Faes EP
quelle