Home > Blockchain >  Get queryset objects grouped by an annotation value range
Get queryset objects grouped by an annotation value range

Time:05-02

I need to filter my objects in a way to get them grouped by range (range is fixed, for this case let's say we have these 3 ranges [0.0, 33.0] [33.01, 66.0] [66.01, 100.0]

here is my model

class Item(models.Model):
    name = models.CharField(
        help_text="Itemname",
        max_length=256
    )
    price = models.DecimalField(max_digits=6, decimal_places=2)

I am trying to get a result that looks like this

{
    "0.0-33.0": [`
        {
            "name": "x"
        }
    ],
    "33.01-66.0": [
        {
            "name": "y"
        },
        {
            "name": "Z"
        }
    ]
}

I tried something like this:

item_by_range = Item.objects.filter(price__lte=100.0).annotate(
    price_group=Case(
        When(price__range=[0.0, 33.0], then=Value('0-33')),
        When(price__range=[33.01, 66.0], then=Value('33-66')),
        When(price__range=[66.01, 100.0], then=Value('66-100')),
        default=Value('No group'),
        output_field=CharField(),
    )
).values('name', 'price_group').order_by('price_group')

but this only works if I pass only price_group in values but this way I lose the name of the item

thanks.

CodePudding user response:

You only need to do some post-processing with groupby(…) [Python-doc] from the itertools module [Python-doc]:

from itertools import groupby
from operator import itemgetter

result = {
    k: [dict(name=v['name']) for v in vs]
    for k, vs in groupby(item_by_range, itemgetter('price_group'))
}

This will make a dictionary that looks like:

{
    "0.0-33.0": [
        {"name": x}
    ],
    "33.01-66.0": [
        {"name": y},
        {"name": z}
    }
}

You can not make an object where the same key (here "name") occurs multiple times.

  • Related