Django Model: Meta: how to have default ordering case-insensitive

Viewed 8962

I am having a Django Model as shown below: I know that we can set the default ordering in the Meta class.

class Ingredient(models.Model):
    name = models.CharField(max_length=200,unique=True,null=False)
    slug = models.SlugField(unique=True)

    class Meta:
        ordering = ["name"]

As the ordering is set to name here. What i found is, it is ordering by case-sensitive. So how to make it case-insensitive

3 Answers

I tested with django 2.0.7 and using Upper works :

class Ingredient(models.Model):
    class Meta:
        ordering = [Upper('name'), ]
name = models.CharField(max_length=200,unique=True,null=False)

It's not possible set the default order to case-insensitive in the model meta options (source).

What you can do is use the order_by method of the QuerySet of your model:

from django.db.models.functions import Lower

Ingredient.objects.order_by(Lower('name'))

As stated already in this answer

To be able to have it as a default ordering (and avoid repeating the order_by method on each one of your querysets), you might want to create a custom Manager class for your Ingredient model:

# managers.py
from django.db.models.functions import Lower

class OrderedIngredientManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().order_by(Lower('name'))

# models.py
from .managers import OrderedIngredientManager

class Ingredient(models.Model):
    name = models.CharField(max_length=200,unique=True,null=False)
    slug = models.SlugField(unique=True)

    ordered_objects = OrderedIngredientManager()

So you can have all your QuerySet ordered:

Ingredient.ordered_objects.all()

You can use it by using F from django models

from django.db.models import F
class Ingredient(models.Model):
    class Meta:
        ordering = [F('name').asc(nulls_last=True)]
Related