Главная > web, Программирование > Django: Решение проблемы с кириллицей при использовании slugify.

Django: Решение проблемы с кириллицей при использовании slugify.

Далее следует более-менее подробное описание проблемы и фикса. Если о проблеме вы в курсе и вас интересует только решение - смело листайте в конец поста.

TL/DR;

В django есть функция для генерации т.н. slug'ов. Перевести одним словом этот термин достаточно сложно, но, кто имеет хоть какой-то опыт работы с django должен знать что это такое. Если раскрыть суть - часть ЧПУ (человеко-понятного URL), которая относится к заголовку сущности. Например, slug для этого поста в терминах django было бы таким: "django-fix-non-latin-slugify" (если я не поменял URL записи после написания этих строк).

Исторически сложилось так, что slug может быть сгенерирован средствами django несколькими способами: с помощью JS в админке (через prepopulated_fields), либо, в самом python-коде с использованием функции slugify (можно ещё в шаблоне с помощью стандартного фильтра slugify, но это то же самое по сути, в отличие от генерации на frontend'е). А всегда, когда не соблюдается принцип DRY - есть вероятность получить разную логику, где она, по идее, должна быть одинакова. Так и вышло, frontend и backend генерируют slug по разному, и если вы пользуетесь последним способом, то это может быть критично - при генерации slug'а на backend'е все не латинские символы будут выкинуты из результата!

Досадная ситуация. Ещё более досадно то, что пофиксить не так уж и сложно, ведь python идёт "в комплекте с батарейками", готовые решения есть - использовать библиотеку unidecode. Но, в django есть политика использовать как можно меньше жёстких внешних зависимостей, поэтому, всё что они сильно захотят использовать у себя "под капотом" - включают в код самого проекта. Так, например, было с библиотекой simplejson, можно найти ещё несколько сторонних пакетов которые живут внутри django. Но, к сожалению (или к счастью), unidecode весит достаточно много и разработчики django не хотят включать его код в свой проект именно по этой причине.

Длинный путь

Ну что ж, благо, это open source, всё в наших руках. Форкать django для правки такой мелочи мы не будем, а воспользуемся monkey-патчингом. Может, это и не очень хорошая техника, но, как мне кажется, это именно тот случай, когда её можно применить. Листинг кода будет совсем короткий:

from django import conf
from django.utils import encoding

try:
# Django 1.5 have some permutations.
from django.utils import text as src_pkg
from django.utils.text import slugify as dj_slugify
except ImportError:
from django.template import defaultfilters as src_pkg
from django.template.defaultfilters import slugify as dj_slugify

import unidecode

def slugify(value):
value = encoding.smart_unicode(value)
return dj_slugify(encoding.smart_unicode(unidecode.unidecode(value)))

if getattr(conf.settings, 'PATCH_SLUGIFY', True):
if not getattr(src_pkg.slugify, 'patched', False):
src_pkg.slugify = slugify
src_pkg.slugify.patched = True

Этот код позволяет как заменить исходную версию slugify, так и просто использовать свою. Если не хотите патчить - поставьте в настройках флаг:
PATCH_SLUGIFY = False

Короткий путь

Если вы не хотите копи-пастить этот костыль, то можете просто установить его с помощью PIP:

pip install -e git+https://github.com/simplylizz/django-slugify.git#egg=django-slugify==1.0.1

И добавить в INSTALLED_APPS приложение "slugify".

Изначально код был протестирован на django 1.4, после выхода 1.5 был подправлен под неё. Есть небольшой шанс, что поддержка ветки 1.4 поломалась - я не проверял. Если у кого будут проблемы - дайте знать.

Возможно, скоро выложу этот пакет на PyPi - я не сторонник захламления этой репы, но проблеме уже года 3 как, судя по соответствующему тикету в django.

Пожалуйста, оцените полезность и качество данной статьи. Одна звезда - плохо, 5 - хорошо.
1/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.2/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.3/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.4/5.5/5. (1 голосов, средний: 5,00 из 5)
Загрузка...
  1. Vlad
    15 сентября 2013 в 01:24 | #1

    Работает шикарно, спасибо.

  1. Пока что нет уведомлений.