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