Перейти к содержимому

Как сделать slug в django

  • автор:

Как автоматически сформировать slug с русского слова?

всё отлично работает, slug автоматически создаётся. Без нареканий.
Но тут возникает мысль, что надо бы уметь создавать записи в бд не только через админку, но и через shell. В связи с этим возникает вопрос — а как тогда будет создаваться slug? ведь он должен создаваться автоматически

в модель добавляется такой код:

def save(self, *args, **kwargs): if not self.id: self.mz_slug = slugify(self.mz_name) super(ModelZavet, self).save(*args, **kwargs)

и всё работает. Создаю новую запись через shell, slug при это не задаю, далее вызываю метод save и вижу что в бд есть новая запись и там автоматически созданный slug.
Но, если поле mz_name, с которого создаётся slug написано по русски, то slug не создаётся. Соответственно всё крашится т.к запись становиться не уникальной и прочий ворох проблем. Почему такое только с русским наименованием, что мне исправить?

  • Вопрос задан более двух лет назад
  • 2995 просмотров

Создание ЧПУ используя slug во фреймворке Python Django

Создание человеко понятных URL в Python Django со slug

Slug — это тип поля в Django для создания понятных URL на латинице. С помощью его мы можем автоматически конвертировать нашу запись, например с заголовком:

Понятный URL! на латинице |
ponyatnyj-url-na-latinice

В этой статье будет рассмотрен пример автоматического создания такой возможности.

Навигация по посту

  • Создание модели
  • Регистрация в admin.py

Создание модели

В модели обязательно должно находится текстовое поле, на которое будет создаваться slug. В основном это тег «» или «». Для примера моя модель в models.py выглядит так:

from django.db import models class News(models.Model): title = models.CharField(max_length=80, null=False) slug = models.SlugField(max_length=70) # Возврат понятного отображения заголовка в панель администрирования def __str__(self): return self.title 

Если не указать максимальную длину поля для SlugField, то оно будет равно 50. По умолчанию, для SlugField создается не кластерный индекс так как «db_index=True».

При этом вы не сможете создать ЧПУ на основе полей: DateTimeField, ForeignKey, OneToOneField, ManyToManyField.

Если есть вероятность того, что поле для создания slug может дублироваться — лучше установить требование к уникальности так как по умолчанию этого не делается:

slug = models.SlugField(max_length=70, unique=True)

Не забудьте выполнить миграцию:

python3 manage.py makemigrations python3 manage.py migrate

Вам так же будет интересно:

Создание первого приложения во фреймворке Python Django 3

Регистрация в admin.py

В файле admin.py мы регистрируем нашу модель для отображения в панели администрирования через атрибут ‘prepopulated_fields’. Мой ‘slug’ будет основан на ‘title’:

from django.contrib import admin from .models import News class PostAdmin(admin.ModelAdmin): prepopulated_fields = admin.site.register(News, PostAdmin)

Теперь, при заполнении заголовка в панели администрирования будет срабатывать JavaScript конвертирующий кириллицу в ASCII.

Создание ЧПУ в Django 3 с использованием prepopulated_fields

Повторное редактирование заголовка у созданной новости не будет изменять slug.

Как сделать slug в django

Django База [2023]: Автоматическое формирование slug, обработка кириллицы в Django #9

Django База [2023]: Автоматическое формирование slug, обработка кириллицы в Django #9

07 января 2023
Оценки статьи
Еще никто не оценил статью

В данном уроке мы научимся работать со slug в Django 4.1, а именно форматировать их автоматически, а также обрабатывать кириллицу в slugField.

Если вы хотите выразить благодарность автору сайта, статей и курса по Django, вы можете сделать это по ссылке ниже:

Что такое Slug?

slug — это тип поля в Django для создания человеко-понятных URL на латинице. С помощью slug мы можем автоматически конвертировать нашу запись, например с заголовком: Добро пожаловать на сайт. В url типа: dobro-pozhalovat-na-sajt.

Есть 2 способа конвертации заголовка в slug, но один работает лишь внутри административной модели, а другой работает всегда. Верно будет использовать оба варианта.

Настройка формирования slug в административной панели

Перейдем в файл admin.py в нашем приложении блог, и изменим код с этого:

blog/admin.py

from django.contrib import admin from mptt.admin import DraggableMPTTAdmin from .models import Category, Article @admin.register(Category) class CategoryAdmin(DraggableMPTTAdmin):  """  Админ-панель модели категорий  """  list_display = ('tree_actions', 'indented_title', 'id', 'title', 'slug')  list_display_links = ('title', 'slug')  prepopulated_fields = 'slug': ('title',)>  admin.site.register(Article) 

blog/admin.py

from django.contrib import admin from mptt.admin import DraggableMPTTAdmin from .models import Category, Article @admin.register(Category) class CategoryAdmin(DraggableMPTTAdmin):  """  Админ-панель модели категорий  """  list_display = ('tree_actions', 'indented_title', 'id', 'title', 'slug')  list_display_links = ('title', 'slug')  prepopulated_fields = 'slug': ('title',)>  @admin.register(Article) class ArticleAdmin(admin.ModelAdmin):  prepopulated_fields = 'slug': ('title',)> 

Пояснение:

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

Смотрим результат в админ-панели:

При вводе любых символов заполняется поле URL

Отлично, все работает. Теперь перейдем ко второму способу.

Добавление функции для сохранения уникального slug, обработка кириллицы с помощью python

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

Результат установки:

(venv) PS C:\Users\Razilator\Desktop\Base\backend> pip install pytils Collecting pytils Using cached pytils-0.4.1-py3-none-any.whl Installing collected packages: pytils Successfully installed pytils-0.4.1 [notice] A new release of pip available: 22.3 -> 22.3.1 [notice] To update, run: python.exe -m pip install --upgrade pip 

Отлично, теперь я создам папку services в папке modules, а внутри два файла init.py и utils.py.

init.py необходим для инициализации папки как пакета Python.

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

Теперь напишем функцию:

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 

Добавление services в INSTALLED_APPS

Далее необходимо добавить наш созданный модуль services в приложения конфигурации Django.

backend/settings.py

INSTALLED_APPS = [  'django.contrib.admin',  'django.contrib.auth',  'django.contrib.contenttypes',  'django.contrib.sessions',  'django.contrib.messages',  'django.contrib.staticfiles',  'modules.blog.apps.BlogConfig',  'modules.services', ] 

Применение уникальных авто-слагов в модели Django

Отлично, функцию написали и модуль добавили в установленные приложения, теперь функцию unique_slugify() необходимо применить в модели Article (Статей).

Для этого переходим в blog/models.py и добавим работу функции при сохранении экземпляра модели.

blog/models.py

from django.db import models from django.core.validators import FileExtensionValidator from django.contrib.auth import get_user_model from django.urls import reverse from mptt.models import MPTTModel, TreeForeignKey from modules.services.utils import unique_slugify class Article(models.Model):  """  Модель постов для сайта  """  STATUS_OPTIONS = (  ('published', 'Опубликовано'),  ('draft', 'Черновик')  )  title = models.CharField(verbose_name='Заголовок', max_length=255)  slug = models.CharField(verbose_name='Альт.название', max_length=255, blank=True, unique=True)  # Другие поля.  # Другие функции.  def __str__(self):  return self.title def get_absolute_url(self):  return reverse('articles_detail', kwargs='slug': self.slug>)  def save(self, *args, **kwargs):  """  Сохранение полей модели при их отсутствии заполнения  """  if not self.slug:  self.slug = unique_slugify(self, self.title)  super().save(*args, **kwargs) 

Пояснение:

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

Давайте протестируем нашу функцию:

Изменяем статью, поле url пустое Генерация slug при сохранении Генерация slug при одинаковых заголовках статей в базе данных

Отлично, у нас все получилось!

Меню категорий

    Загрузка категорий.

Добавляем слаги (slug) к URL-адресам

На этом занятии мы сделаем отображение отдельных статей по их слагу (slug). Если кто не знает, то slug – это уникальный фрагмент URL-адреса, ассоциированный с конкретной записью и, обычно, состоит из набора маленьких латинских букв, цифр, символов подчеркивания и дефиса. Например, статья «Арифметические операции» на сайте https://proproprogs.ru доступна по следующему адресу:

Здесь slug – это последние символы, по которым и выбирается данная страница из БД. Использование слагов – рекомендуемая практика в веб-программировании. Такие страницы лучше ранжируются поисковыми системами и понятнее конечному пользователю.

Давайте вначале сделаем отображение статей по их идентификатору, а затем, заменим адрес на слаг. У нас уже есть функция-заглушка show_post() в файле women/views.py. Мы ее перепишем, следующим образом:

def show_post(request, post_id): post = get_object_or_404(Women, pk=post_id) context = { 'post': post, 'menu': menu, 'title': post.title, 'cat_selected': 1, } return render(request, 'women/post.html', context=context)

Здесь функция get_object_or_404 выбирает одну запись из таблицы Women, которая имеет идентификатор, равный post_id, либо генерирует исключение 404, если запись не была найдена. Это довольно частая операция, когда нужно найти какую-либо отдельную запись, а в противном случае, перенаправить пользователя на заготовленную страницу 404. Поэтому в Django для таких случаев заготовлена специальная функция.

Далее, формируется словарь из параметров шаблона и отображается страница на основе шаблона post.html. У нас пока нет такого файла, добавим его со следующим содержимым:

{% extends 'women/base.html' %} {% block content %} h1>{{post.title}}/h1> {% if post.photo %} p>img class="img-article-left" src=">">/p> {% endif %} {post.content} {% endblock %}

Здесь все достаточно очевидно. Вначале отображаем заголовок h1, затем, фотографию статьи, если она есть, ну и потом уже содержимое самой статьи.

Если теперь перейти по ссылке, то увидим полноценную статью. Если же указать неверный адрес, то получим исключение 404. Повторю еще раз, исключения в таком развернутом виде отображаются только в режиме отладки сайта. При эксплуатации с константой DEBUG = False вместо исключения отображается заготовленная страница 404.

Добавление слага

Следующим шагом сделаем отображение статей по их слагу. Но откуда нам его взять? Для этого в модели Women необходимо прописать еще одно поле, которое так и назовем – slug:

class Women(models.Model): title = models.CharField(max_length=255, verbose_name="Заголовок") slug = models.SlugField(max_length=255, unique=True, db_index=True, verbose_name="URL") .

Я его определил после поля title, указал уникальным, индексируемым и имя URL, отображаемое в админке. Однако, если сейчас попытаться создать миграцию для внесения этих изменений в структуру таблицы women:

python manage.py makemigrations

то увидим предупреждение, что поле не может быть пустым (так как у нас есть записи в таблице). Чтобы таблицы были сформированы как надо, я решил создать БД заново. Поэтому сразу добавил такое же поле в модели Category:

class Category(models.Model): name = models.CharField(max_length=100, db_index=True, verbose_name="Категория") slug = models.SlugField(max_length=255, unique=True, db_index=True, verbose_name="URL") .

Удалим все файлы миграций, прежний файл БД и выполним команду

python manage.py makemigrations

для создания первой мигации. Затем, с помощью команды:

python manage.py migrate

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

python manage.py createsuperuser

с именем root, почтой root@coolsite.ru и паролем 1234. Запускаем веб-сервер и заходим в админ-панель.

Для начала добавим категории. Здесь нам предлагается ввести ее название и слаг (URL). Конечно, можно заполнить оба поля вручную, например, «Актрисы» и «actrisi». Но, так как слаг, обычно, повторяет заголовок, только записанный латиницей, то фреймворк Django позволяет этот процесс автоматизировать. Давайте откроем файл women/admin.py и для модели Category в классе CategoryAdmin добавим атрибут:

prepopulated_fields = {"slug": ("name", )}

Это специальное свойство, которое указывает фреймворку автоматически заполнять поле slug по данным поля name.

Возвращаемся в админку, обновляем страницу и, смотрите, при вводе строки в поле name, автоматически формируется поле slug. Это очень здорово и значительно облегчает нашу работу. Теперь можно совершенно спокойно добавить две рубрики «Актрисы» и «Певицы».

Далее, прежде чем добавлять статьи, сделаем такую же связку по слагу для модели Women в классе WomenAdmin:

prepopulated_fields = {"slug": ("title",)}

только здесь мы указываем поле title. Возвращаемся в админ-панель и на вкладке добавления женщин введем информацию по актрисам:

Анджелина Джоли, Дженнифер Лоуренс, Джулия Робертс, Марго Робби, Ума Турман

А также по певицам:

Ариана Гранде, Бейонсе, Кэтти Перри, Рианна, Шакира

Отлично, база данных готова и теперь можно сделать отображение статей по слагу. Для этого откроем файл women/urls.py и в списке urlpatterns изменим маршрут для постов на следующий:

path('post//', show_post, name='post'),

Затем, в файле women/views.py немного поменяем функцию представления show_post:

def show_post(request, post_slug): post = get_object_or_404(Women, slug=post_slug) .

И в модели Women (в файле women/models.py) будем формировать URL-адрес по параметру slug:

class Women(models.Model): . def get_absolute_url(self): return reverse('post', kwargs={'post_slug': self.slug}) .

Все, обновляем главную страницу сайта и видим, что теперь посты доступны по слагу, а не идентификатору. Этот пример показывает как в Django легко и просто можно менять URL-адреса и вместо id использовать другие поля, в частности, слаг. При этом, мы не производили совершенно никаких изменений в шаблонах, благодаря использованию метода get_absolute_url() в модели Women. Кроме того, Django автоматически защищает такие адреса от SQL-инъекций, когда злоумышленник пытается выполнить SQL-запрос, прописывая его в адресной строке браузера. Благодаря всем этим мелочам, которые берет на себя фреймворк, даже начинающий веб-мастер может конструировать вполне безопасные сайты с богатым функционалом.

Аналогичную операцию использования слагов можно сделать и для отображения рубрик. Предлагаю вам выполнить это самостоятельно для закрепления материала.

Видео по теме

#1. Django — что это такое, порядок установки

#2. Модель MTV. Маршрутизация. Функции представления

#3. Маршрутизация, обработка исключений запросов, перенаправления

#4. Определение моделей. Миграции: создание и выполнение

#5. CRUD — основы ORM по работе с моделями

#6. Шаблоны (templates). Начало

#7. Подключение статических файлов. Фильтры шаблонов

#8. Формирование URL-адресов в шаблонах

#9. Создание связей между моделями через класс ForeignKey

#10. Начинаем работу с админ-панелью

#11. Пользовательские теги шаблонов

#12. Добавляем слаги (slug) к URL-адресам

#13. Использование форм, не связанных с моделями

#14. Формы, связанные с моделями. Пользовательские валидаторы

#15. Классы представлений: ListView, DetailView, CreateView

#16. Основы ORM Django за час

#17. Mixins — убираем дублирование кода

#18. Постраничная навигация (пагинация)

#19. Регистрация пользователей на сайте

#20. Делаем авторизацию пользователей на сайте

#21. Оптимизация сайта с Django Debug Toolbar

#22. Включаем кэширование данных

#23. Использование капчи captcha

#24. Тонкая настройка админ панели

#25. Начинаем развертывание Django-сайта на хостинге

#26. Завершаем развертывание Django-сайта на хостинге

© 2024 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *