如何将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(因为它处于循环状态,因此无法使用)?

Answers:


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

关于评论的更新

有多种方法可以做到这一点。一种方法(就内存和时间而言,这可能不是最好的一种方法)是完全相同的:

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?
约翰

我将其标记为正确,因为我对过滤器一无所知,并且忘记了lambda。
约翰2010年

315

为什么不叫list()Queryset

answers_list = list(answers)

这还将评估QuerySet/ run查询。然后,您可以从该列表中删除/添加。


9
请注意这一点。当您将其强制转换为aa列表时,独特的标志可能会被忽略。
rh0dium15年

我可以独立进行操作,但是可以在Django形式的queryset中进行操作。知道为什么吗?
ismailsunni 2015年

如果是这样,则转换为set,然后返回list以获得唯一的。
radtek

36

遵循您的实际意图有点困难。您的第一条语句看起来像是您两次获取相同的QuerySet一样。首先通过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()。在您的情况下,您可能需要添加可选的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谢谢!
Cho

18

通过使用带有step参数的slice运算符,这将导致对查询集的评估并创建一个列表。

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())这似乎违反直觉。
geoidesic '19

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 queryset转换为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()用于删除

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.