Let’s say I have the following Django model.

from django.db import models

class User(models.Model):
    name = models.CharField(blank=True)

And I want to filter those like so.

users = User.objects.filter(name__istartswith="John")

That would perform the following query.

SELECT "data_user"."id", "data_user"."name"
FROM "data_user"
WHERE UPPER("data_user"."name"::text) LIKE UPPER('John%')

I can improve the performance of that query by adding the following index to the model. To complement the use of UPPER() in the query I can use the Upper() function for the index’s expression.

from django.db import models
from django.db.models.functions import Upper

class User(models.Model):
    name = models.CharField(blank=True)

    class Meta:
        indexes = [
            models.Index(Upper("name"), name="name_idx"),
        ]

As name could be blank, I can improve the index by adding the following condition to only index rows where the name isn’t blank.

from django.db import models
from django.db.models.functions import Upper

class User(models.Model):
    name = models.CharField(blank=True)

    class Meta:
        indexes = [
            models.Index(
                Upper("name"),
                name="name_idx",
                condition=~models.Q(name=Upper(models.Value(""))),
            ),
        ]

Thanks to Tim Bell I learnt that for the condition I needed to pass models.Value("") as the argument to the Upper() function. Previously, I was only passing an empty string condition=~models.Q(name=Upper("")), and whilst Django successfully created a migration for that index, when attempting to migrate I got the following error raised.

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, data, sessions
Running migrations:
  Applying data.0001_initial...Traceback (most recent call last):
  File "project/src/manage.py", line 22, in <module>
    main()
  ...
  File "project/.venv/lib/python3.12/site-packages/django/db/models/sql/query.py", line 1772, in names_to_path
    raise FieldError(
django.core.exceptions.FieldError: Cannot resolve keyword '' into field. Choices are: id, question_text

It appears in this incorrect case Upper("") is referring to applying the function Upper() to the nonexistent model field named "".