Output of values() on a QuerySet with ManyToMany fields

Viewed 13939

I'm currently placing the result of a QuerySet into a JSON string to be used by my js frontend.

Currently this is easy enough using .values() and simplejson:

simplejson.dumps(list(Task.objects.filter(list=mylist).values()))

I've now added a ManyToMany field in my Task object, would like to have it included in my output without having each Task object repeated for every value of the ManyToMany relationship.

If I just did Task.objects.filter(list=mylist).values('myManyToManyField', 'someOtherField') The output would have a separate object/row for each value of myManyToManyField

[{'myManyToManyField': 1, 'someOtherField': 'valueOne'}, 
{'myManyToManyField': 2, 'someOtherField': 'valueOne'},
{'myManyToManyField': 1, 'someOtherField': 'valueTwo'}]

Is there any way to get this result instead?:

[{'myManyToManyField': [1,2], 'someOtherField': 'valueOne'},
{'myManyToManyField': 1, 'someOtherField': 'valueTwo'}]

The only solution I have right now is to loop over all the Task objects and build the output manually, placing the ManyToMany value within it as desired. Is there a better way to do this? If not - would this be horribly inefficient?

3 Answers
from django.contrib.postgres.aggregates import ArrayAgg

Task.objects.filter(list=mylist).annotate(arr_field=ArrayAgg('myManyToManyField')).values('arr_field', 'someOtherField')

Output:

[{'arr_field': [1,2], 'someOtherField': 'valueOne'},
 {'arr_field': 1, 'someOtherField': 'valueTwo'}]

You can use Django's serializers:

import json
from django.core import serializers

json_data = serializers.serialize("json", Task.objects.all())

If you want to extract the fields only, do the following:

data = [i['fields'] for i in json.loads(json_data)]
Related