Изменение по числам в Django
11 октября 2009 :: 2 комментария :: 2837 просмотров :: 627 слов

В шаблонизаторе django очень много встроенных тегов, которые неплохо помогают в рутинных ситуациях, таких как вывод списка юзеров из массива, удаление пробелов, вывод списка по алфавиту. Все это и многое другое можно прочитать в документации к django:
http://docs.djangoproject.com/en/dev/ref/templates/builtins/

Обладая мощной системой шаблонов все-таки нельзя учесть все пожелания пользователей, а особенно говорящих на разных языках. Именно для этого разработчики и придумали пользовательские теги, позволяющие самому дописать функционал.

В документации есть такой фильтр как pluralize, позволяющий дописывать к числу заданное слово в нужном падеже. Синтаксис его таков:

You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}

Однако вот беда - для русского языка это совершенно не подходит. В английском числа различаются только "одно что-то" и "много чего-то", с соответствующим добавлением окончания -s или других его производных (-es, -ies). В русском может быть три варианта окончаний "один кабачок", "два-три-четыре кабачка", "пять кабачков". Да еще нужно учитывать, что все зависит от последней цифры числа ("двадцать один кабачок"). Да еще у нас есть такие числа как "одиннадцать", "двенадцать" и "тринадцать", которые не поддаются этому правилу. В общем все намного сложнее, чем в английском. Поэтому нам просто необходимо написать свой custom-фильтр.

Мною был взят код, когда-то давно написанный themylogin'ом у себя в wiki для PHP. В определенных пределах он меня вполне устроил.

Все это было переписано на Python'е и вставлено в качестве custom-tag'а в проект django. О создании и правильном размещении подробнее можно прочитать в документации, я опишу вкратце.

У меня есть application "main", создадим папку main/templatetags/, в которую положим пустой файл init.py (чтобы Python признал ее как часть проекта) и файл с названием pluralize.py

Далее пропишем 'mysite.main' (где mysite - название проекта) в INSTALLED_APPS в вашем settings.py, чтобы теперь django признал его.

Далее пишем в pluralize,py (Cтарый вариант. Плохо работает при больших числах)

# -*- coding: utf-8 -*-

# Стандартный импорт библиотеки шаблонов
from django import template

# Это чтобы register.filter работал
register = template.Library()

# Расскажем django о нашем крутом фильтре
@register.filter
def rupluralize(value, arg="дурак,дурака,дураков"):

    # Берем модуль от нашего числа
    number = abs(int(value))

    # Так как фильтр поддерживает лишь один аргумент, разбиваем его по запятым
    args = arg.split(",")

    # Ну а тут основная магия
    if (number % 100 == 1) or (number % 100 > 20) and (number % 10 == 1):
        return args[0]
    if (number % 100 == 2) or (number % 100 > 20) and (number % 10 == 2):
        return args[1]
    if (number % 100 == 3) or (number % 100 > 20) and (number % 10 == 3):
        return args[1]
    if (number % 100 == 4) or (number % 100 > 20) and (number % 10 == 4):
        return args[1]
    return args[2]

Обновленный вариант
По алгоритму GNU: http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html

# -*- coding: utf-8 -*-

# Стандартный импорт библиотеки шаблонов
from django import template

# Это чтобы register.filter работал
register = template.Library()

# Расскажем django о нашем крутом фильтре
@register.filter
def rupluralize(value, arg="дурак,дурака,дураков"):
    args = arg.split(",")
    number = abs(int(value))
    a = number % 10
    b = number % 100

    if (a == 1) and (b != 11):
        return args[0]
    elif (a >= 2) and (a <= 4) and ((b < 10) or (b >= 20)):
        return args[1]
    else:
        return args[2]

Написание фильтра закончено. Прицепим его в шаблоне, написав где-нибудь в начале:

{% load pluralize %}

И потом используем:

  • {{ user.mails }} {{ user.mails|rupluralize:"письмо,письма,писем" }}
  • {{ user.posts }} {{ user.posts|rupluralize:"статья,статьи,статей" }}
  • {{ user.comments }} {{ user.comments|rupluralize:"комментарий,комментария,комментариев" }}

  • </ul>
    </code>

    И получаем примерно вот такое:

    Ну или вот так можно:

Еще? Тогда вот
Комментарии ↓
Автор топ :: 17 июня 2019 в 15:05 из Kazan’, RU #
0

Святой человек. Спас от дедлайна.

Дмитрий :: 15 сентября 2019 в 13:02 из Moscow, RU #
0

Спасибо тебе! Добрый человек!!!

Комментирование доступно только членам Вастрик.Клуба

Войти через Патреон Войти через Клуб