Как преобразовать 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)

Прочтите, когда QuerySets оцениваются, и обратите внимание, что нецелесообразно загружать весь результат в память (например, через list()).

Ссылка: itertools.ifilter

Обновление относительно комментария:

Это можно сделать разными способами. Один (который, вероятно, не лучший с точки зрения памяти и времени) - сделать то же самое:

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. Можно ли как-то использовать для этого ifilter?
Джон

Я отмечу это как правильное, потому что я не знал о фильтре и забыл о лямбдах.
Джон

315

Почему бы просто не позвонить list()на Queryset?

answers_list = list(answers)

Это также оценит QuerySet/ запустит запрос. Затем вы можете удалить / добавить из этого списка.


9
Будьте осторожны с этим. Когда вы передаете это в список, отдельный флаг может не приниматься во внимание.
rh0dium 01

Я могу сделать это независимо, но могу сделать это в наборе запросов в форме django. Есть идеи, почему?
ismailsunni

Если да, то примените к, setа затем вернитесь к, listчтобы получить уникальные.
radtek 06

36

Сложно уследить за тем, что вы действительно пытаетесь сделать. Ваш первый оператор выглядит так, как будто вы дважды получаете один и тот же точный QuerySet of Answer объектов. Сначала через, answer_set.answers.all()а затем снова через .filter(id__in=...). Дважды проверьте оболочку и посмотрите, даст ли она вам список ответов, которые вы ищете:

answers = answer_set.answers.all()

После того, как вы очистили это, чтобы вам (и другим, работающим над кодом) было немного легче читать, вы можете изучить .exclude () и поиск по полю __in .

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

new_answers = answers.exclude(question_answer__in=existing_question_answers)

Вышеупомянутый поиск может не синхронизироваться с определениями вашей модели, но он, вероятно, поможет вам достаточно близко, чтобы завершить работу самостоятельно.

Если вам все еще нужен список значений идентификаторов, вы можете поиграть с .values_list () . В вашем случае вы, вероятно, захотите добавить необязательный параметр flat = True.

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

Спасибо за Ваш ответ. К сожалению, я не предоставил достаточно подробностей, чтобы показать, что я не могу использовать ваш подход.
Джон

1
Лучшее решение описанной проблемы. Я хочу добавить new_answers = answers.exclude(question_answer__in=existing_question_answers.values_list('id', flat=True))@istruble
aquaman

Самый чистый способ - 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 не поддерживает отрицательную индексацию.
Алексей Сидаш

Ладно Алексей. Вы прямо здесь. Я обновил ответ.
Анкит Сингх

16

Вы можете напрямую конвертировать, используя listключевое слово. Например:

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

Используя приведенный выше код, вы можете напрямую преобразовать результат набора запроса в файл list.

Вот listключевое слово, которое objявляется результатом набора запросов и list1является переменной в той переменной, в которой мы сохраняем преобразованный результат, который в list.


1
Но если вы сделаете это, это не сработает: list1 = list(emp.objects.all())что кажется нелогичным.
geoidesic

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, которые вы делаете для списка.


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)

в приведенном выше коде он удаляет все объекты из qs с идентификатором '1'

дополнительная информация : -

filter()используется для выбора определенных объектов, но exclude()используется для удаления

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.