В чём проблема
По логике реализации slugify, при allow_unicode=False текст нормализуется и кодируется в ASCII с отбрасыванием символов, которых там нет. Кириллица в ASCII отсутствует, поэтому русские буквы пропадают. Для заголовка «Привет мир» результат — пустая строка.
Параметр allow_unicode
С allow_unicode=True русские буквы остаются в slug. Это решает проблему пустого значения, но адрес остаётся кириллическим. Если нужна латиница, потребуется транслитерация. Шаблонный фильтр slugify параметр allow_unicode не принимает (запрос на это закрыт: предлагается написать свой фильтр).
Готовая функция по таблице Яндекса
Функция работает по таблице генератора. Её можно подключить в методе save() модели или в pre_save:
import re
YANDEX = {
'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e',
'ё': 'e', 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k',
'л': 'l', 'м': 'm', 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r',
'с': 's', 'т': 't', 'у': 'u', 'ф': 'f', 'х': 'h', 'ц': 'c',
'ч': 'ch', 'ш': 'sh', 'щ': 'shh', 'ъ': '', 'ы': 'y', 'ь': '',
'э': 'e', 'ю': 'yu', 'я': 'ya',
}
def yandex_slug(text):
out = "".join(YANDEX.get(ch, ch) for ch in text.lower())
out = re.sub(r"[^a-z0-9]+", "-", out)
return out.strip("-")
Для «Щёлково цех юг» функция даёт shhelkovo-ceh-yug, как и генератор.
Не забывайте про уникальность
Если два заголовка дадут один slug, поле с ограничением unique вызовет ошибку. Добавляйте суффикс при совпадении: «Генерация уникального слага при коллизиях». Особенно важно, если slug может получиться пустым.
Связанные статьи
Маршруты со слагами в Django — в статье «Роутинг в Django: слаги и уникальность».
Источники
Описание основано на обсуждении в трекере Django и коде функции. Проверьте поведение на вашей версии.
Типичные ошибки
- Использовать slugify без allow_unicode для русских заголовков.
- Хранить пустой slug: он ломает уникальность.
- Использовать allow_unicode и ожидать латиницу.
- Менять slug опубликованной записи без редиректа.
Пошагово: приводим адреса к единому виду
- Найдите в проекте модели, где slug создаётся из заголовка.
- Подключите функцию
yandex_slugвместоslugify. - Добавьте проверку уникальности.
- Для существующих записей пересчитайте slug одной командой управления.
- Для опубликованных записей настройте редиректы.
Разбор заголовка по шагам
Возьмём заголовок «Как выбрать беговые кроссовки» и пройдём путь до адреса. Функция превращает заголовок в slug при сохранении модели.
Заголовок: Как выбрать беговые кроссовки
Без служебных слов: Как выбрать беговые кроссовки
Адрес целиком: kak-vybrat-begovye-krossovki
Адрес короче: kak-vybrat-begovye-krossovki
Режим «Убрать служебные слова» в генераторе делает второй шаг сам. Короткий адрес читается легче и лучше помещается в строку браузера. Ограничения по длине и другие правила составления адреса собраны в статье «Как составить ЧПУ-адрес страницы».
Памятка для редактора
Если в проекте несколько редакторов, дайте им короткую памятку. Достаточно этих правил:
- Свою функцию — для русских заголовков.
- Проверяем уникальность и пустое значение.
- Меняем slug — с редиректом.
Чек-лист
- Не использовать slugify без allow_unicode для русского.
- Подключить функцию в save().
- Проверять уникальность.
- При смене slug настраивать редирект.
Частые вопросы
Почему slugify возвращает пустую строку для русского заголовка?
В режиме по умолчанию он оставляет только ASCII-символы, а кириллицы там нет.
Что делает allow_unicode=True?
Оставляет русские буквы в slug: адрес получается кириллическим.
Как получить латинский slug?
Написать функцию транслитерации и вызвать её в save() модели.
Что делать при совпадении slug?
Добавлять суффикс и проверять уникальность перед сохранением.
Проверьте свои заголовки: вставьте их в генератор ЧПУ и посмотрите, как в адресе выглядят слова с этой буквой.