Django QuerySetをリストに変換する方法


121

私は以下を持っています:

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

じゃあ後で:

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)

エラーが発生します:

'QuerySet' object has no attribute 'remove'

QuerySetを標準セットまたはリストに変換するためにあらゆる種類のことを試しました。何も機能しません。

QuerySetから項目を削除して、データベースから削除せず、新しいQuerySetを返さないようにするにはどうすればよいですか(機能しないループにあるため)。

回答:


42

あなたはこれを行うことができます:

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)

QuerySetが評価されたときに読み取り結果全体をメモリにロードするのは適切ではないことに注意してください(例:を介してlist())。

参照: itertools.ifilter

コメントに関して更新

これにはさまざまな方法があります。1つ(おそらく、メモリと時間の点で最善ではない)は、まったく同じことを行うことです。

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)

上記のコードサンプルに1行追加して、exising_question_answersから同じエントリを削除しました。どういうわけかそれのためにifilterを使用することは可能ですか?
john

フィルターについて知らず、ラムダについて忘れていたので、これを正しいものとしてマークします。
john

315

なぜ単に呼びかけないlist()Querysetですか?

answers_list = list(answers)

これによりQuerySet、クエリの/ run も評価されます。その後、そのリストから削除/追加できます。


9
これに注意してください。これをリストにキャストすると、個別のフラグが無視される場合があります。
rh0dium

私は独立してそれを行うことができますが、django形式のクエリセットでそれを行うことができます。なぜだと思いますか?
ismailsunni 2015年

もしそうなら、次にキャストしsetて次に戻りlist、ユニークなものを取得します。
radtek、

36

あなたが本当にやろうとしていることを理解するのは少し難しいです。最初のステートメントは、Answerオブジェクトのまったく同じQuerySetを2回フェッチしているように見えます。最初に経由しanswer_set.answers.all()、次に再び経由し.filter(id__in=...)ます。シェルを再確認して、探している回答のリストが表示されるかどうかを確認します。

answers = answer_set.answers.all()

それをクリーンアップすると、あなた(およびコードに取り組んでいる他の人)が読むのが少し簡単になるので、.exclude()__in フィールドlookupを調べることをお勧めします。

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

new_answers = answers.exclude(question_answer__in=existing_question_answers)

上記のルックアップはモデル定義と同期しない可能性がありますが、おそらく自分でジョブを完了するのに十分近くなります。

それでもid値のリストを取得する必要がある場合は、.values_list()試してください。あなたの場合、おそらくオプションのflat = Trueを追加したいと思うでしょう。

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

ご回答有難うございます。残念ながら、私はあなたのアプローチを使用できないことを示すのに十分な詳細を提供しませんでした。
john

1
記述された問題の最善の解決策。new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@istrubleを追加したい
アクアマン

最もきれいな方法はflat=Trueありがとう!!!!!!!
チョ

18

クエリセットの評価を引き起こし、リストを作成するステップパラメータを持つスライス演算子を使用する。

list_of_answers = answers[::1]

または最初にあなたがしたかもしれない:

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

私の知る限り、django querysetは負のインデックスをサポートしていません。
Alexey Sidash 16

さてアレクセイ。あなたはここにいます。答えを更新しました。
Ankit Singh

15

listキーワードを使用して直接変換できます。例えば:

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

上記のコードを使用すると、クエリセットの結果をに直接変換できますlist

これlistはキーワードでありobj、クエリセットの結果でありlist1、その変数には変数が含まれていますlist


1
しかし、これを行っても機能しませんlist1 = list(emp.objects.all())。直感に反するようです。
ジオイデシック

4

単に、.values('reqColumn1','reqColumn2')または.values_list('reqColumn1','reqColumn2')クエリセットで呼び出さないのはなぜ ですか?

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

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

または

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

result = [(value1,value2)]

このQuerySetですべての操作を行うことができます。これはlistに対して行うものです。


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)

このコードは、djangoクエリセットをpythonリストに変換します


0

これを試してください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)

指定された列値のリストを返します


0

関数の代わりに、クエリセットからオブジェクトを削除remove()できますexclude()。構文は似ていますfilter()

:-

qs = qs.exclude(id= 1)

上記のコードでは、ID「1」のqsからすべてのオブジェクトを削除します

追加情報:-

filter()特定のオブジェクトを選択exclude()するために使用されますが、削除するために使用されます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.