Склонение слов во множественном числе в шаблонах 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 подписчиков