Bagaimana mengonversi Django QuerySet menjadi daftar

121

Saya memiliki yang berikut ini:

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

lalu nanti:

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)

Saya mendapatkan kesalahan:

'QuerySet' object has no attribute 'remove'

Saya sudah mencoba segala cara untuk mengubah QuerySet menjadi set standar atau daftar. Tidak ada yang berhasil.

Bagaimana cara saya menghapus item dari QuerySet sehingga tidak menghapusnya dari database, dan tidak mengembalikan QuerySet baru (karena itu dalam loop yang tidak berfungsi)?

john
sumber

Jawaban:

42

Anda bisa melakukan ini:

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)

Baca saat QuerySets dievaluasi dan perhatikan bahwa tidak baik untuk memuat seluruh hasil ke dalam memori (misalnya vialist()).

Referensi: itertools.ifilter

Pembaruan terkait dengan komentar:

Ada berbagai cara untuk melakukan ini. Satu (yang mungkin bukan yang terbaik dalam hal memori dan waktu) adalah melakukan hal yang persis sama:

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
sumber
Saya telah menambahkan satu baris lagi ke contoh kode saya di atas, menghapus entri yang sama dari exising_question_answers. apakah mungkin menggunakan ifilter untuk itu juga?
john
Saya akan menandai ini sebagai benar karena saya tidak tahu tentang filter dan lupa tentang lambda.
john
315

Mengapa tidak hanya panggilan list()pada Queryset?

answers_list = list(answers)

Ini juga akan mengevaluasi QuerySet/ menjalankan kueri. Anda kemudian dapat menghapus / menambahkan dari daftar itu.

Zeppomedio
sumber
9
Hati-hati dengan ini. Ketika Anda mentransmisikan ini ke daftar, bendera yang berbeda dapat diabaikan.
rh0dium
Saya dapat melakukannya secara mandiri, tetapi saya dapat melakukannya dalam queryset dalam bentuk django. Tahu kenapa?
ismailsunni
Jika demikian, maka lemparkan ke setdan kemudian kembali ke listuntuk mendapatkan yang unik.
radtek
36

Agak sulit untuk mengikuti apa yang sebenarnya Anda coba lakukan. Pernyataan pertama Anda sepertinya Anda mengambil objek QuerySet of Answer yang persis sama dua kali. Pertama melalui answer_set.answers.all()dan kemudian melalui .filter(id__in=...). Periksa kembali di shell dan lihat apakah ini akan memberi Anda daftar jawaban yang Anda cari:

answers = answer_set.answers.all()

Setelah Anda membersihkannya sehingga sedikit lebih mudah bagi Anda (dan orang lain yang mengerjakan kode) untuk membaca, Anda mungkin ingin melihat .exclude () dan pencarian bidang __in .

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

new_answers = answers.exclude(question_answer__in=existing_question_answers)

Pencarian di atas mungkin tidak sinkron dengan definisi model Anda, tetapi mungkin akan membuat Anda cukup dekat untuk menyelesaikan pekerjaan sendiri.

Jika Anda masih perlu mendapatkan daftar nilai id maka Anda ingin bermain dengan .values_list () . Dalam kasus Anda, Anda mungkin ingin menambahkan flat opsional = True.

answers.values_list('id', flat=True)
tidak bisa rusak
sumber
Terima kasih atas jawaban anda. Sayangnya saya tidak memberikan cukup detail untuk menunjukkan bahwa saya tidak dapat menggunakan pendekatan Anda.
john
1
Solusi terbaik untuk masalah yang dijelaskan. Saya ingin menambahkan new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@istruble
aquaman
Cara terbersih adalah flat=TrueTerima kasih !!!!!!!
Cho
18

Dengan menggunakan operator slice dengan parameter step yang akan menyebabkan evaluasi queryset dan membuat daftar.

list_of_answers = answers[::1]

atau awalnya Anda bisa melakukan:

answers = Answer.objects.filter(id__in=[answer.id for answer in
        answer_set.answers.all()])[::1]
Ankit Singh
sumber
Sejauh yang saya tahu, django queryset tidak mendukung pengindeksan negatif.
Alexey Sidash
Oke Alexey. Anda ada di sini. Saya telah memperbarui jawabannya.
Ankit Singh
15

Anda dapat langsung mengonversi menggunakan listkata kunci. Sebagai contoh:

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

Dengan menggunakan kode di atas, Anda dapat langsung mengubah hasil set kueri menjadi list .

Berikut listadalah kata kunci dan objhasil dari set kueri dan list1variabel dalam variabel itu kita menyimpan hasil konversi yang masuk list.

patel shahrukh
sumber
1
Tetapi jika Anda melakukan ini, itu tidak berhasil: list1 = list(emp.objects.all())yang tampaknya kontra-intuitif.
geoidesic
4

Mengapa tidak menelepon saja .values('reqColumn1','reqColumn2')atau .values_list('reqColumn1','reqColumn2')di queryset?

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

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

ATAU

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

result = [(value1,value2)]

Anda bisa melakukan semua operasi pada QuerySet ini, yang Anda lakukan untuk daftar.

Piyush S. Wanare
sumber
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)

kode ini mengubah django queryset ke daftar python

EunSeong Lee
sumber
0

Coba ini 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)

Ini akan mengembalikan Anda daftar dengan nilai kolom tertentu

Sakeer
sumber
0

alih-alih remove()Anda dapat menggunakan exclude()fungsi untuk menghapus objek dari queryset. sintaksnya mirip denganfilter()

mis . : -

qs = qs.exclude(id= 1)

dalam kode di atas itu menghapus semua objek dari qs dengan id '1'

info tambahan : -

filter()digunakan untuk memilih objek tertentu tetapi exclude()digunakan untuk menghapus

Muhammed Faes EP
sumber