Django QuerySet'i listeye dönüştürme


121

Aşağıdakilere sahibim:

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

daha sonra:

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)

Bir hata alıyorum:

'QuerySet' object has no attribute 'remove'

QuerySet'i standart bir kümeye veya listeye dönüştürmek için her türlü yöntemi denedim. Hiç birşey çalışmıyor.

Bir öğeyi QuerySet'ten nasıl kaldırabilirim, böylece onu veritabanından silmesin ve yeni bir QuerySet döndürmesin (çünkü çalışmayacak bir döngüde olduğu için)?

Yanıtlar:


42

Bunu yapabilirsin:

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)

QuerySets değerlendirildiğinde okuyun ve sonucun tamamını belleğe (örn. Aracılığıyla list()) yüklemenin iyi olmadığını unutmayın .

Referans: itertools.ifilter

Yorumla ilgili güncelleme :

Bunu yapmanın çeşitli yolları vardır. Biri (muhtemelen hafıza ve zaman açısından en iyisi değildir) tamamen aynı şeyi yapmaktır:

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)

Exising_question_answers'dan aynı girişi silerek yukarıdaki kod örneğime bir satır daha ekledim. Bunun için de bir şekilde ifiltre kullanmak mümkün mü?
John

Bunu doğru olarak işaretleyeceğim çünkü filtreyi bilmiyordum ve lambdaları unutmuştum.
John

315

Neden sadece çağrı list()üzerine Queryset?

answers_list = list(answers)

Bu aynı zamanda QuerySetsorguyu / çalıştırmayı da değerlendirecektir . Daha sonra bu listeden kaldırabilir / ekleyebilirsiniz.


9
Buna dikkat et. Bunu bir listeye attığınızda, farklı bayrak göz ardı edilebilir.
rh0dium

Bunu bağımsız olarak yapabilirim, ancak django formunda sorgu setinde yapabilirim. Herhangi bir fikrin neden?
ismailsunni

Öyleyse , benzersiz olanları elde setetmek listiçin öğesine ve ardından geri dönün .
radtek

36

Gerçekten yapmaya çalıştığınız şeyi takip etmek biraz zor. İlk ifadeniz, aynı QuerySet of Answer nesnelerini iki kez getiriyor gibi görünüyor. Önce yoluyla answer_set.answers.all()ve sonra tekrar yoluyla .filter(id__in=...). Kabuğu iki kez kontrol edin ve bunun size aradığınız cevapların listesini verip vermeyeceğine bakın:

answers = answer_set.answers.all()

Bunu temizledikten sonra, sizin (ve kod üzerinde çalışan diğerlerinin) okuması biraz daha kolay olur, .exclude () ve __in alan aramasına bakmak isteyebilirsiniz .

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

new_answers = answers.exclude(question_answer__in=existing_question_answers)

Yukarıdaki arama, model tanımlarınızla uyumlu olmayabilir, ancak muhtemelen işi kendiniz bitirmenize yetecek kadar yaklaşmanızı sağlayacaktır.

Yine de bir id değerleri listesi almanız gerekiyorsa, o zaman .values_list () ile oynamak istersiniz . Sizin durumunuzda, muhtemelen isteğe bağlı düz = True eklemek isteyeceksiniz.

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

Cevabınız için teşekkürler. Ne yazık ki yaklaşımınızı kullanamayacağımı gösterecek kadar ayrıntı vermedim.
John

1
Tanımlanan sorun için en iyi çözüm. new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@
İstruble

En temiz yol flat=TrueTeşekkürler !!!!!!!
Cho

18

Sorgu kümesinin değerlendirilmesine ve bir liste oluşturulmasına neden olacak adım parametresiyle dilim operatörünün kullanılmasıyla.

list_of_answers = answers[::1]

veya başlangıçta şunları yapabilirdin:

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

Bildiğim kadarıyla django sorgu kümesi negatif indekslemeyi desteklemiyor.
Alexey Sidash

Tamam Alexey. Tam buradasın. Cevabı güncelledim.
Ankit Singh

16

listAnahtar kelimeyi kullanarak doğrudan dönüştürebilirsiniz . Örneğin:

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

Yukarıdaki kodu kullanarak bir sorgu kümesi sonucunu doğrudan bir list.

Burada listanahtar kelime ve objsorgu kümesinin sonucudur ve list1bu değişkendeki dönüştürülmüş sonucu sakladığımız değişkendir list.


1
Ancak bunu yaparsanız işe yaramaz: list1 = list(emp.objects.all())bu sezgiye aykırı görünüyor.
geoidesic

4

Neden sadece arama .values('reqColumn1','reqColumn2')veya .values_list('reqColumn1','reqColumn2')sorgu setinde değil?

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

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

VEYA

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

result = [(value1,value2)]

Liste için yaptığınız tüm işlemleri bu QuerySet üzerinde yapabilirsiniz.


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)

bu kod django sorgu setini python listesine dönüştürür


0

Bunu dene 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)

Size belirtilen sütun değerlerine sahip bir liste döndürür


0

bunun yerine, bir nesneyi sorgu kümesinden kaldırmak için işlevi remove()kullanabilirsiniz exclude(). sözdizimi şuna benzer:filter()

örneğin : -

qs = qs.exclude(id= 1)

Yukarıdaki kodda, qs'den '1' kimliğine sahip tüm nesneleri kaldırır.

ek bilgi : -

filter()belirli nesneleri seçmek için kullanılır, ancak exclude()kaldırmak için kullanılır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.