Склонение слов во множественном числе в шаблонах Django

В заметке ниже описывается как сделать собственный шаблонный фильтр Django для склонения русских слов во множественном числе.

Например мы делаем социальную сеть где люди могут подписываться друг на друга, а  на странице профиля пользователя мы хотим видеть количество его подписчиков.

Здесь возникает необходимость добавлять различное окончание к слову подписчик:

  • 1 подписчик
  • 3 подписчика
  • 20 подписчиков

В шаблонизаторе Django есть фильтр для множественного числа pluralize https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#pluralize, он работает следующим образом (возьмем пример из документации):

You have {{ num_messages }} message{{ num_messages|pluralize }}.

Код выше будет работать так:

Если num_messages содержит 1 , результат будет «You have 1 message«.

Если num_messages содержит 2, результат будет «You have 2 messages«.

Т.е. к слову message в случае множественного числа добавляется «s«.

Только для русского языка фильтр pluralize не подходит, поскольку может быть три варианта окончаний. Например у нас «подписчик», «подписчика», «подписчиков». Поэтому напишем свой фильтр Джанго для окончаний для множественного числа в русском языке.

Процесс создания собственного фильтра я описывать не буду, посмотрите в официальной документации https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/

В двух словах.

Собственные фильтры и теги Джанго необходимо размещать в приложении внутри каталога templatetags.

Например у нас есть приложение users, создадим в нем папку  templatetags/ (не забудим добавить в нее пустой файл __init__.py) и в нем файл в котором будет хранить наши фильтры и теги — users_extras.py. В итоге у нас должна получается такая структура:

Создание собственного фильтра Джанго

Кстати, это имя файла нам понадобится в шаблонах, когда захотим использовать наши собственные фильтры и теги.

В шаблоне нужно будет указать

{% load users_extras %}

Создаем наш фильтр и регистрируем его в Джанго, для этого добавим в users_extras.py:

from django import template

register = template.Library()


@register.filter
def ru_plural(value, variants):
    variants = variants.split(",")
    value = abs(int(value))

    if value % 10 == 1 and value % 100 != 11:
        variant = 0
    elif value % 10 >= 2 and value % 10 <= 4 and \
            (value % 100 < 10 or value % 100 >= 20):
        variant = 1
    else:
        variant = 2

    return variants[variant]

Теперь фильтр готов, давайте протестируем.

Не забываем перезапускать отладочный сервер Джанго, если был запущен.

В начальной задачи нам необходимо было выводить разные окончания у слова подписчик. Предположим у нас в шаблоне подписчики выводятся так:

{{ total_followers }} подписчик

Заменим слово подписчик на наш фильтр:

{{ total_followers|ru_plural:"подписчик,подписчика,подписчиков" }}

Теперь все отображается корректно, как надо.

  • 1 подписчик
  • 3 подписчика
  • 20 подписчиков

Хостинг для ваших проектов