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-патчингом. Может, это и не очень хорошая техника, но, как мне кажется, это именно тот случай, когда её можно применить. Листинг кода будет совсем короткий:

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

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

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

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

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

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

Понравилась статья? Поделиться с друзьями:
Комментариев: 1
  1. Vlad

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

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: