在具有ManyToMany字段的QuerySet上输出values()

xqw*_*zts 11 django django-orm django-queryset

我目前正在将QuerySet的结果放入我的js前端使用的JSON字符串中.

目前使用.values()和simplejson很容易:

simplejson.dumps(list(Task.objects.filter(list=mylist).values()))
Run Code Online (Sandbox Code Playgroud)

我现在在我的Task对象中添加了一个ManyToMany字段,希望将它包含在我的输出中,而不必为ManyToMany关系的每个值重复每个Task对象.

如果我只是做了Task.objects.filter(list=mylist).values('myManyToManyField', 'someOtherField') 输出将为每个值有一个单独的对象/行myManyToManyField

[{'myManyToManyField': 1, 'someOtherField': 'valueOne'}, 
{'myManyToManyField': 2, 'someOtherField': 'valueOne'},
{'myManyToManyField': 1, 'someOtherField': 'valueTwo'}]
Run Code Online (Sandbox Code Playgroud)

有没有办法得到这个结果?:

[{'myManyToManyField': [1,2], 'someOtherField': 'valueOne'},
{'myManyToManyField': 1, 'someOtherField': 'valueTwo'}]
Run Code Online (Sandbox Code Playgroud)

我现在唯一的解决方案是遍历所有Task对象并手动构建输出,根据需要将ManyToMany值放在其中.有一个更好的方法吗?如果不是 - 这会非常低效吗?

小智 20

from django.contrib.postgres.aggregates import ArrayAgg

Task.objects.filter(list=mylist).annotate(arr_field=ArrayAgg('myManyToManyField')).values('arr_field', 'someOtherField')
Run Code Online (Sandbox Code Playgroud)

输出:

[{'arr_field': [1,2], 'someOtherField': 'valueOne'},
 {'arr_field': 1, 'someOtherField': 'valueTwo'}]
Run Code Online (Sandbox Code Playgroud)

  • 哇,非常感谢,这绝对应该被接受的答案! (2认同)

小智 3

看来除了迭代所有Task对象之外没有其他办法了。

Django 的文档警告在“ManyToManyField”上使用“values()”。

它不会是

效率极低

如果你这样做多对多字段的所有值:Django