ForWork
ForWork

Reputation: 13

Django values method - related objects in list

Hi help with values () method of queryset. When displaying related fields (Foreign key), the data is repeated, can this data be grouped?

class Product(models.Model):
    category = models.ForeignKey(Category, related_name='product', on_delete=models.CASCADE)
    title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=250, unique=True, db_index=True)

class ProductImage(models.Model):
    product = models.ForeignKey(Product, related_name='product_image', on_delete=models.CASCADE)
    image = models.ImageField(upload_to='img/models/')
    is_main = models.BooleanField()

View code

data = Product.objects.all().values('pk', 'title', 'product_image')

Example here

This is how it is displayed

[
    {'pk': 1, 'title': 'Product 1', 'product_image__image': 'img/models/mod_wpYzlnm.png'}, 
    {'pk': 2, 'title': 'Product 2', 'product_image__image': 'img/models/mod2_wEr0D2q.png'},
    {'pk': 2, 'title': 'Product 2', 'product_image__image': 'img/models/mod_pPQqmjB_we175uR.png'},
    {'pk': 10, 'title': 'Product 3', 'product_image__image': 'img/models/mod_3mTxkb9_z4lKV3l.png'}, 
    {'pk': 10, 'title': 'Product 3', 'product_image__image': 'img/models/heart.png'}
]

This is how it should be

[
    {'pk': 1, 'title': 'Product 1, 'product_image':[ 
        {'image':'img/models/mod_wpYzlnm.png'}
    ]}, 
    {'pk': 2, 'title': 'Product 2', 'product_image': [
        {'image':'img/models/mod2_wEr0D2q.png'}, 
        {'image':'img/models/mod_pPQqmjB_we175uR.png'}
    ]},
    {'pk': 10, 'title': 'Product 3',  'product_image': [
        {'image':'img/models/mod_3mTxkb9_z4lKV3l.png'}, 
        {'image':'img/models/heart.png'}
    ]}, 
]

Upvotes: 1

Views: 1017

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476659

You should post-process the data with the groupby(…) function [python-doc] of the itertools module [python-doc]. For the query we should however first order on the pk, or at least an item such that the queryset ProductImages is order such that all ProductImages of the same Product are next of each other.

We can thus transform this with:

from itertools import groupby
from operator import itemgetter

data = Product.objects.values('pk', 'title', 'product_image').order_by('pk')

result = [
    {'pk': pk, 'title': title,
    'product_image': [ {'image': pi['product_image__image'] } for pi in pis ] }
    for (pk, title), pis in groupby(data, itemgetter('pk', 'title'))
]

for the given sample data, this gives us:

[{'pk': 1,
  'product_image': [{'image': 'img/models/mod_wpYzlnm.png'}],
  'title': 'Product 1'},
 {'pk': 2,
  'product_image': [{'image': 'img/models/mod2_wEr0D2q.png'},
                    {'image': 'img/models/mod_pPQqmjB_we175uR.png'}],
  'title': 'Product 2'},
 {'pk': 10,
  'product_image': [{'image': 'img/models/mod_3mTxkb9_z4lKV3l.png'},
                    {'image': 'img/models/heart.png'}],
  'title': 'Product 3'}]

Upvotes: 1

Related Questions