Django 5 для начинающих

Прогресс по курсу:  9/1004

10.4 Работа с DetailView, форматирование и обработка кириллицы в Slug
2 из 4 шагов пройдено
0 из 8 баллов  получено

Сообщим Django, что нужно предзаполнять поле slug данными, вводимыми в поле title, используя атрибут prepopulated_fields.


Для этого в файле admin.py изменим следующий код:

admin.site.register(Post)


На следующий: 

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    """
    Админ-панель модели записей
    """
    prepopulated_fields = {'slug': ('title',)}


Мы добавили параметр prepopulated_fields, который позволяет с помощью встроенного JS обрабатывать заголовок в реальном времени, конвертирует даже кириллицу. Перейдем в админ панель, и попробуем добавить новую статью.


И мы видим, что при добавлении названии статьи, у нас автоматически заполняется поле Slug (URL). Заполним все остальные поля и добавим ее. Теперь попробуем добавить еще одну статью с таким же именем, мы получим ошибку, так как такое Slug уже существует:


Давайте сделаем уникализацию наших слагов, первым делом для обработки кириллицы в поле slug, нам нужно модернизировать функцию slugify(), для этого установим пакет pytils с помощью терминала:

pip install pytils

Pytils это инструменты для работы с русскими строками (транслитерация, числительные словами, русские даты и т.д.) 

Теперь создадим папку services в папке apps, а внутри её создадим файл utils.py:


В файл utils.py мы будем добавлять различные полезные функции для нашего проекта, поэтому мы ее отделим от приложения блог. В дальнейшем это будет более удобно для разработки и доработки нашего проекта.

Добавим в apps/services/utils.py следующий код обработки:

from uuid import uuid4
from pytils.translit import slugify


def unique_slugify(instance, slug):
    """
    Генератор уникальных SLUG для моделей, в случае существования такого SLUG.
    """
    model = instance.__class__
    unique_slug = slugify(slug)
    while model.objects.filter(slug=unique_slug).exists():
        unique_slug = f'{unique_slug}-{uuid4().hex[:8]}'
    return unique_slug


Теперь функцию unique_slugify() необходимо добавить в модели Post (Статей).

from apps.services.utils import unique_slugify


class Post(models.Model):
    """
    Модель постов для нашего блога
    """
    slug = models.SlugField(verbose_name='URL', max_length=255, blank=True)
    # Поля модели и метакласс

    # Функции str и get_absolute_url

    def save(self, *args, **kwargs):
        """
        При сохранении генерируем слаг и проверяем на уникальность
        """
        self.slug = unique_slugify(self, self.title)
        super().save(*args, **kwargs)

Первым делом мы удалим unique=True в поле slug, так как проверку уникальности мы передали функции unique_slugify

Мы импортировали функцию по генерации slug, а также добавили метод save для обработки полей экземпляра. В условии, если нет slug, то мы генерируем slug из заголовка, а если такой slug существует, то мы добавляем символы uuid4.

Выполним миграции:

python manage.py makemigrations
python manage.py migrate


Давайте проверим работу, запустим сервер и перейдем в админ панель. Попробуем создать еще раз запись, у которой совпадает название:

Нажмем кнопку СОХРАНИТЬ, и мы видим что наша запись успешно создалась.

Попробуем перейти в запись и посмотрим её слаг.

Мы видим что наша функция успешно отработала, слаг стал уникальным используя uuid4.


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

Мне для реализации автоматически генерируемого слага понравился подход с unidecode, использовал его в прошлой версии блога - переводить все не-ASCII символы в ASCII используя более поддерживаемый unidecode, и дальше вызывать встроенную slugify():

from django.utils.text import slugify
from unidecode import unidecode

def slugify_function(content: str) -> str:
    """
    Creates slug from unidecoded content using standard Django slugify()
    :param content: text to create slug from
    :return: slug
    """
    return slugify(unidecode(content))

Unidecode очень простой, поддерживается перекодировка из множества языков, не только из кириллицы.

А для поддержки уникальности попробовал так же иной подход. На другом курсе усвоил активное использование django-extensions, многие ресурсы продвигают эту библиотеку как must have. В том числе в ней реализованы расширения моделей - поле AutoSlugField, и абстрактные классы, в том числе TitleSlugDescriptionModel - он реализует три поля, которые мы в этом приложении создаем руками, а именно title, description и self-managed slug, причем для последнего автоматически обеспечивается генерация из title и уникальность путем прибавления постфикса -2, -3 и т.д.
Для этого в модели нужно определить метод slugify_function():

    def slugify_function(self, content):
        return slugify_function(content)

Метод save() при этом можно не трогать.

Использовал и в Post, и в Category, и там и там работает как необходимо. Один момент - поле slug скрыто в админке - что не напрягает, т.к. о нем вообще не нужно беспокоиться

Изменен ilya kutaev
def save(self, *args, **kwargs):
        """
        Сохранение полей модели при их отсутствии заполнения
        """

почему при отсутствии,  где условие для пустого поля, можете пояснить пожалуйста как работает save может я не так понимаю 

Изменен Шамбер Егор

мы же просто преобразуем полученные данные для сохранения в бд и здесь нет проверки на пустоту

@Шамбер_Егор, Перефразировал чтобы было понятнее. Спасибо.