Jak przekonwertować zestaw Django QuerySet na listę

121

Mam:

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

potem później:

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)

Pojawia się błąd:

'QuerySet' object has no attribute 'remove'

Próbowałem przerobić QuerySet na standardowy zestaw lub listę. Nic nie działa.

Jak mogę usunąć element z QuerySet, aby nie usuwał go z bazy danych i nie zwracał nowego zestawu QuerySet (ponieważ jest w pętli, która nie działa)?

Jan
źródło

Odpowiedzi:

42

Możesz to zrobić:

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)

Przeczytaj, kiedy QuerySets są oceniane i zauważ, że nie jest dobrze ładować cały wynik do pamięci (np. Via list()).

Odniesienie: itertools.ifilter

Aktualizacja dotycząca komentarza:

Można to zrobić na różne sposoby. Jednym (który prawdopodobnie nie jest najlepszy pod względem pamięci i czasu) jest zrobienie dokładnie tego samego:

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
źródło
dodałem jeszcze jeden wiersz do powyższego przykładu kodu, usuwając ten sam wpis z exising_question_answers. czy można w jakiś sposób użyć do tego filtra ifilter?
Jan
Oznaczę to jako poprawne, ponieważ nie wiedziałem o filtrze i zapomniałem o lambdach.
john
315

Dlaczego nie po prostu zadzwoń list()po Queryset?

answers_list = list(answers)

Spowoduje to również ocenę QuerySet/ uruchom zapytanie. Następnie możesz usunąć / dodać z tej listy.

Zeppomedio
źródło
9
Ostrożnie z tym. Kiedy rzucasz to na listę, odrębna flaga może zostać zignorowana.
rh0dium
Mogę to zrobić niezależnie, ale mogę to zrobić w queryset w postaci django. Każdy pomysł, dlaczego?
ismailsunni
Jeśli tak, rzuć do, seta potem z powrotem, listaby uzyskać unikalne.
radtek
36

Trochę trudno jest śledzić to, co naprawdę próbujesz zrobić. Twoje pierwsze stwierdzenie wygląda na to, że możesz dwukrotnie pobrać dokładnie te same obiekty QuerySet of Answer. Najpierw przez, answer_set.answers.all()a potem ponownie przez .filter(id__in=...). Dokładnie sprawdź w powłoce i zobacz, czy da ci to listę odpowiedzi, których szukasz:

answers = answer_set.answers.all()

Po wyczyszczeniu tego, aby czytanie było trochę łatwiejsze dla Ciebie (i innych osób pracujących nad kodem), możesz zajrzeć do .exclude () i wyszukiwania pól __in .

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

new_answers = answers.exclude(question_answer__in=existing_question_answers)

Powyższe wyszukiwanie może nie zsynchronizować się z definicjami modelu, ale prawdopodobnie zbliży Cię na tyle, aby samemu zakończyć pracę.

Jeśli nadal potrzebujesz listy wartości identyfikatorów, powinieneś pobawić się z .values_list () . W twoim przypadku prawdopodobnie będziesz chciał dodać opcjonalny flat = True.

answers.values_list('id', flat=True)
istruble
źródło
Dziękuję za odpowiedź. Niestety nie podałem wystarczająco szczegółów, aby pokazać, że nie mogę zastosować twojego podejścia.
john
1
Najlepsze rozwiązanie opisanego problemu. Chcę dodać new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@istruble
aquaman
Najczystszym sposobem jest flat=Truedzięki !!!!!!!
Cho
18

Poprzez użycie operatora wycinka z parametrem step, który spowodowałby ocenę zestawu zapytań i utworzenie listy.

list_of_answers = answers[::1]

lub początkowo mogłeś zrobić:

answers = Answer.objects.filter(id__in=[answer.id for answer in
        answer_set.answers.all()])[::1]
Ankit Singh
źródło
O ile wiem, django queryset nie obsługuje indeksowania ujemnego.
Alexey Sidash
Ok, Alexey. Jesteś tutaj. Zaktualizowałem odpowiedź.
Ankit Singh
16

Możesz bezpośrednio konwertować za pomocą listsłowa kluczowego. Na przykład:

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

Używając powyższego kodu możesz bezpośrednio przekonwertować wynik zestawu zapytań na plik list.

Oto listsłowo kluczowe i objjest wynikiem zestawu zapytań i list1jest zmienną w tej zmiennej, w której przechowujemy przekonwertowany wynik, w którym list.

patel shahrukh
źródło
1
Ale jeśli to zrobisz, nie zadziała: list1 = list(emp.objects.all())co wydaje się sprzeczne z intuicją.
geoidesic
4

Dlaczego po prostu nie zadzwonić .values('reqColumn1','reqColumn2')lub nie .values_list('reqColumn1','reqColumn2')włączyć zestawu zapytań?

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

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

LUB

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

result = [(value1,value2)]

Możesz wykonać wszystkie operacje na tym QuerySet, które wykonujesz dla list.

Piyush S. Wanare
źródło
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)

ten kod konwertuje zestaw zapytań django na listę Pythona

EunSeong Lee
źródło
0

Spróbuj tego 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)

Zwróci listę z określonymi wartościami kolumn

Sakeer
źródło
0

zamiast remove()ciebie możesz użyć exclude()funkcji do usunięcia obiektu z zestawu zapytań. jego składnia jest podobna dofilter()

np . : -

qs = qs.exclude(id= 1)

w powyższym kodzie usuwa wszystkie obiekty z qs o id '1'

dodatkowe informacje : -

filter()służy do wybierania określonych obiektów, ale exclude()służy do usuwania

Muhammed Faes EP
źródło