Когда пользователь открывает страницу фильма на сайте, в адресной строке браузера мы обычно видим не что-то вроде:
https://cinemahub.com/movies/23/
а более понятный и "человеческий" адрес:
https://cinemahub.com/movies/interstellar/
Вот этот последний фрагмент (interstellar) и называется slug — короткое, уникальное, читаемое название для URL.
Оно обычно формируется из латинских букв, цифр и дефисов, и помогает пользователям (и поисковым системам) лучше понимать, что находится на странице.
Slug — это строка, которая служит уникальным идентификатором записи в URL.
Он похож на id, но при этом более дружелюбен к пользователю. Например:
| Запись | URL с ID | URL со slug |
|---|---|---|
| Интерстеллар | /movies/23/ |
/movies/interstellar/ |
| Начало | /movies/24/ |
/movies/inception/ |
Таким образом, slug — это часть SEO и удобства навигации.
Откроем модель Movie в models.py и добавим новое поле slug:
from django.db import models
class Movie(models.Model):
title = models.CharField(max_length=255, verbose_name="Название")
slug = models.SlugField(max_length=255, db_index=True, blank=True, default='', verbose_name="URL")
description = models.TextField(blank=True, verbose_name="Описание")
release_year = models.IntegerField(default=2000, verbose_name="Год выпуска")
def __str__(self):
return self.titleТеперь выполним миграции, чтобы Django добавил это поле в базу данных:
python manage.py makemigrations
python manage.py migrateЕсли фильмы уже есть в базе данных, им нужно выдать временные slug. Откроем интерактивную оболочку Django:
python manage.py shellи выполним:
from movies.models import Movie
for movie in Movie.objects.all():
movie.slug = f"movie-{movie.pk}"
movie.save()Теперь у всех фильмов появится уникальный slug вроде movie-1, movie-2 и т.д.
После этого можно запретить пустые значения и установить уникальность, чтобы в будущем нельзя было создать два одинаковых slug:
slug = models.SlugField(max_length=255, db_index=True, unique=True, verbose_name="URL")И снова применяем миграции:
python manage.py makemigrations
python manage.py migrateТеперь давайте настроим так, чтобы фильм открывался по адресу /movies/interstellar/, а не /movies/23/.
Откроем файл movies/urls.py и добавим маршрут:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='home'),
path('movie/<slug:movie_slug>/', views.show_movie, name='movie'),
]Здесь <slug:movie_slug> — это динамическая часть URL, в которую Django будет подставлять значение slug конкретного фильма.
Теперь обновим views.py:
from django.shortcuts import render, get_object_or_404
from .models import Movie
def show_movie(request, movie_slug):
movie = get_object_or_404(Movie, slug=movie_slug)
return render(request, 'movies/movie_detail.html', {'movie': movie})Теперь можно открыть в браузере:
http://127.0.0.1:8000/movie/interstellar/
и увидеть страницу фильма.
Когда мы работаем с шаблонами, нам часто нужно создавать ссылки на конкретный объект.
Например, в списке фильмов (index.html) мы хотим сделать кнопку «Подробнее»:
<a href="/movie/interstellar/">Подробнее</a>Но если в будущем мы изменим маршруты, нам придется переписывать все ссылки.
Чтобы избежать этого, Django предлагает метод get_absolute_url().
Добавим его в нашу модель Movie:
from django.urls import reverse
class Movie(models.Model):
title = models.CharField(max_length=255, verbose_name="Название")
slug = models.SlugField(max_length=255, db_index=True, unique=True, verbose_name="URL")
description = models.TextField(blank=True, verbose_name="Описание")
release_year = models.IntegerField(default=2000, verbose_name="Год выпуска")
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('movie', kwargs={'movie_slug': self.slug})Теперь Django сам подставит нужный URL, когда мы вызовем этот метод.
В шаблоне index.html, где мы отображаем список фильмов, теперь можно использовать:
{% for movie in movies %}
<h2>{{ movie.title }}</h2>
<p>{{ movie.description|truncatewords:20 }}</p>
<a href="{{ movie.get_absolute_url }}">Подробнее</a>
{% endfor %}Django автоматически построит правильный адрес для каждого фильма.
Если вы поменяете структуру маршрутов в urls.py, всё продолжит работать без изменений в шаблонах.
- Перейдите на главную страницу
/movies/. - Кликните на ссылку "Подробнее".
- Проверьте, что открывается страница конкретного фильма.
- Попробуйте вручную ввести адрес
/movie/interstellar/— убедитесь, что Django находит нужный фильм.
Метод get_absolute_url() — это стандарт Django.
Его используют не только в шаблонах, но и во встроенных механизмах, например, в админке или при сериализации объектов.
Он позволяет централизованно управлять URL — если вы когда-нибудь решите поменять структуру маршрутов, всё продолжит работать.
Это мощный инструмент, который делает код устойчивым к изменениям и удобным для расширения.
- Добавьте slug в модель
Genre, чтобы жанры фильмов также открывались по URL вида/genre/drama/. - Создайте шаблон
genre_detail.html, который отображает все фильмы этого жанра. - Добавьте метод
get_absolute_url()в модельGenre. - Проверьте, что при клике на жанр в списке фильмов вы переходите на его страницу.
- Измените slug одного из фильмов вручную через shell и убедитесь, что ссылка на фильм автоматически обновилась.
- Попробуйте ввести несуществующий slug в адресной строке — посмотрите, как работает
get_object_or_404.
- Что такое slug и зачем он используется в Django?
- Почему slug должен быть уникальным?
- Как добавить slug в модель и сделать его обязательным?
- Что делает метод
get_absolute_url()? - Почему в
get_absolute_url()мы используем функциюreverse()? - Как в шаблоне получить ссылку на конкретный объект модели?
- Что произойдет, если вызвать
get_object_or_404()с несуществующим slug? - Чем slug лучше числового ID в URL?
- Можно ли изменить slug после создания записи? Что произойдет со старыми ссылками?
- Почему важно централизованно управлять URL через
get_absolute_url()?