← Назад к вопросам

Что такое reverse в Django?

2.4 Senior🔥 91 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое reverse в Django

reverse() — это функция в Django, которая преобразует имя URL паттерна в его фактический URL. Вместо того чтобы хардкодить URLs в шаблонах и коде, используется имя маршрута, а reverse() динамически генерирует правильный URL. Это основной механизм для поддержки DRY принципа в Django приложениях.

Базовое использование

1. urls.py — определяем именованные маршруты:

from django.urls import path
from . import views

urlpatterns = [
    path('articles/', views.article_list, name='article_list'),
    path('articles/<int:pk>/', views.article_detail, name='article_detail'),
    path('articles/<int:pk>/edit/', views.article_edit, name='article_edit'),
    path('users/<str:username>/', views.user_profile, name='user_profile'),
]

2. Использование reverse() в views:

from django.shortcuts import redirect
from django.urls import reverse
from .models import Article

def create_article(request):
    # Создаём новую статью
    article = Article.objects.create(title='New Article')
    
    # Вместо хардкода '/articles/1/'
    # используем reverse для динамического создания URL
    url = reverse('article_detail', kwargs={'pk': article.pk})
    
    return redirect(url)  # Редирект на /articles/1/

3. Использование в шаблонах (тег {% url %}):

<!-- вместо хардкода /articles/1/ используем тег url -->
<a href="{% url 'article_detail' pk=article.pk %}">Читать статью</a>

<!-- С параметрами -->
<a href="{% url 'user_profile' username=user.username %}">Профиль</a>

<!-- Без параметров -->
<a href="{% url 'article_list' %}">Все статьи</a>

reverse_lazy() для декораторов

from django.urls import reverse_lazy
from django.contrib.auth.decorators import login_required
from django.views.generic import DetailView

# reverse_lazy используется, когда URL нужен при загрузке модуля
# (когда reverse() ещё не может быть вычислен)

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'article_detail.html'
    login_url = reverse_lazy('login')  # URL вычисляется при доступе

@login_required(login_url=reverse_lazy('login'))
def protected_view(request):
    return render(request, 'protected.html')

Примеры с параметрами

from django.urls import reverse

# urls.py
# path('posts/<int:year>/<int:month>/', views.archive, name='archive')

# views.py или templates
url = reverse('archive', kwargs={'year': 2025, 'month': 3})
print(url)  # '/posts/2025/3/'

# С одним параметром
url = reverse('article_detail', kwargs={'pk': 42})
print(url)  # '/articles/42/'

# С query параметрами (не входят в kwargs)
url = reverse('article_list')
url_with_query = f'{url}?filter=new&sort=date'
print(url_with_query)  # '/articles/?filter=new&sort=date'

Обработка NoReverseMatch

from django.urls import reverse, NoReverseMatch

try:
    url = reverse('non_existent_view')
except NoReverseMatch:
    print('URL паттерн не найден')
    url = '/fallback/'

Использование в моделях

from django.urls import reverse
from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=100)
    
    def get_absolute_url(self):
        """Возвращает URL для этого объекта"""
        return reverse('article_detail', kwargs={'pk': self.pk})

# Использование
article = Article.objects.first()
print(article.get_absolute_url())  # '/articles/1/'

# Автоматический редирект после создания
from django.views.generic import CreateView

class ArticleCreateView(CreateView):
    model = Article
    fields = ['title']
    # Django автоматически редиректит на get_absolute_url()

reverse() с namespaces

# urls.py (главный)
from django.urls import path, include

urlpatterns = [
    path('blog/', include('blog.urls', namespace='blog')),
    path('shop/', include('shop.urls', namespace='shop')),
]

# blog/urls.py
app_name = 'blog'
urlpatterns = [
    path('articles/', views.list, name='list'),
    path('articles/<int:pk>/', views.detail, name='detail'),
]

# shop/urls.py
app_name = 'shop'
urlpatterns = [
    path('products/', views.list, name='list'),
    path('products/<int:pk>/', views.detail, name='detail'),
]

# Использование
from django.urls import reverse

# Для блога
blog_url = reverse('blog:list')      # '/blog/articles/'
blog_detail = reverse('blog:detail', kwargs={'pk': 1})  # '/blog/articles/1/'

# Для магазина
shop_url = reverse('shop:list')      # '/shop/products/'
shop_detail = reverse('shop:detail', kwargs={'pk': 1})  # '/shop/products/1/'

reverse() в API responses

from django.urls import reverse
from django.http import JsonResponse

def api_create_article(request):
    article = Article.objects.create(title='New Article')
    
    return JsonResponse({
        'id': article.id,
        'title': article.title,
        'url': reverse('article_detail', kwargs={'pk': article.pk})
    })

# Ответ:
# {
#   "id": 1,
#   "title": "New Article",
#   "url": "/articles/1/"
# }

Сравнение подходов

❌ НЕПРАВИЛЬНО (хардкод):

# Если изменим URL в urls.py, сломаем всё
def article_detail(request, pk):
    article = Article.objects.get(pk=pk)
    return redirect(f'/articles/{pk}/')  # Хардкод!

# В шаблоне
<a href="/articles/{{ article.pk }}/">Ссылка</a>  # Хардкод!

✅ ПРАВИЛЬНО (использование reverse):

from django.urls import reverse

def article_detail(request, pk):
    article = Article.objects.get(pk=pk)
    return redirect(reverse('article_detail', kwargs={'pk': pk}))

# В шаблоне
<a href="{% url 'article_detail' pk=article.pk %}">Ссылка</a>

Практический пример: REST API

from django.urls import reverse
from rest_framework import serializers
from .models import User

class UserSerializer(serializers.ModelSerializer):
    url = serializers.SerializerMethodField()
    
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'url']
    
    def get_url(self, obj):
        return self.context['request'].build_absolute_uri(
            reverse('user_detail', kwargs={'pk': obj.pk})
        )

# Результат
# {
#   "id": 1,
#   "username": "alice",
#   "email": "alice@example.com",
#   "url": "http://example.com/users/1/"
# }

Обработка ошибок

from django.urls import reverse, NoReverseMatch
from django.shortcuts import render

def safe_reverse(url_name, **kwargs):
    """Безопасная версия reverse с обработкой ошибок"""
    try:
        return reverse(url_name, kwargs=kwargs)
    except NoReverseMatch:
        # Логируем ошибку
        import logging
        logger = logging.getLogger(__name__)
        logger.error(f'URL {url_name} с параметрами {kwargs} не найден')
        return '/'

# Использование
url = safe_reverse('non_existent')  # Вернёт '/'

URL версионирование

# urls.py
from django.urls import re_path

urlpatterns = [
    re_path(r'^v1/articles/(?P<pk>\d+)/$', views.article_v1, name='article_v1'),
    re_path(r'^v2/articles/(?P<pk>\d+)/$', views.article_v2, name='article_v2'),
]

# Использование
from django.urls import reverse

v1_url = reverse('article_v1', kwargs={'pk': 1})  # '/v1/articles/1/'
v2_url = reverse('article_v2', kwargs={'pk': 1})  # '/v2/articles/1/'

Performance: кэширование URLs

from django.urls import reverse
from django.views.decorators.cache import cache_page

@cache_page(60 * 5)  # Кэш на 5 минут
def article_list(request):
    # reverse() очень быстра, кэширование не критично
    # но может помочь при очень большом количестве URL'ов
    articles = Article.objects.all()
    return render(request, 'list.html', {'articles': articles})

Best Practices

✅ ВСЕГДА:

  • Используй reverse() или тег {% url %} вместо хардкода
  • Определяй get_absolute_url() в моделях
  • Используй reverse_lazy() в settings и декораторах
  • Именуй URL паттерны по их смыслу (article_detail, не ad)

❌ НИКОГДА:

  • Не хардкодь URLs
  • Не используй reverse() с пользовательским вводом без валидации
  • Не забывай обрабатывать NoReverseMatch в критичных местах
reverse() — это фундамент чистого и масштабируемого Django приложения. Она позволяет менять URL структуру без обновления кода, только изменяя urls.py.
Что такое reverse в Django? | PrepBro