Як перетворити запит набору Джанго в список


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
Будьте обережні з цим. Якщо ви подаєте це до списку aa, то окремий прапор може не враховуватися.
— rh0dium

Я можу це зробити самостійно, але можу це зробити в наборі запитів у формі джанго. Будь-яка ідея чому?
— ismailsunni

Якщо так, то киньте на, setа потім назад, listщоб отримати унікальні.
— radtek

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)

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

Якщо вам все-таки потрібно отримати список значень id, тоді ви хочете пограти з .values_list () . У вашому випадку ви, ймовірно, захочете додати необов’язковий плоский = 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 не підтримує негативну індексацію.
— Олексій Сидаш

Гаразд, Олексій. Ви тут. Я оновив відповідь.
— Анкіт Сінгх

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


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 з id '1'

додаткова інформація : -

filter()використовується для вибору конкретних об'єктів, але exclude()використовується для видалення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.