How to apply a function on the values selected in Django queryset?

Viewed 1027

Say I'm having the below model in Django

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    volumes = JSONField()

I want to get the length of title of all the Books as values -

[
    {
        "id": 1,
        "volumes": [
            {
                "order": 1
            },
            {
                "order": 2
            }
        ],
        "length_of_volumes": 2
    },
]

I tried the following, but it's not the proper way to do it as it's not a CharField -

from django.db.models.functions import Length
Books.objects.all().values('id', 'title', length_of_valumes=Length('volumes'))
3 Answers

len('title') will just determine the length of the string 'title' which thus has five characters, so as .values(…), you use .values(length_of_title=5).

You can make use of the Length expression [Django-doc]:

from django.db.models.functions import Length

Books.objects.values('id', 'title', length_of_title=Length('title'))

Note: normally a Django model is given a singular name, so Book instead of Books.

Similar to Willem's answer, but uses annotation. Taken from https://stackoverflow.com/a/34640020/14757226.

from django.db.models.functions import Length
qs = Books.objects.annotate(length_of_title=Length('title')).values('id', 'title', 'length_of_title')

An advantage would be you can then add filter or exclude clauses to query on the length of the title. So if you only wanted results where the title was less than 10 characters or something.

You can use dict structure:

values = []
for b in Books.objects.all().values('id', 'title'):
    values.append({
            'id': b.id, 
            'title': b.title, 
            'length_of_title': len(b.title) 
    })
Related