Шаблонный тег url

Курс по Django: https://stepik.org/a/183363

Архив проекта: 13_sitewomen.zip

Следующий важный шаг при разработке шаблонов – научиться правильно прописывать URL-адреса для ссылок. Я напомню, что ссылки в HTML-документе формируются с помощью тега <a> по следующему правилу:

<a href="URL-адрес страницы">Название ссылки</a>

Например, мы можем в шаблоне index.html добавить ссылки для чтения поста следующим образом:

<ul>
         {% for p in posts %}
         {% if p.is_published %}
         <li>
                   <h2>{{p.title}}</h2>
                   <p >{{p.content}}</p>
                   <p ><a href="post/{{p.id}}/">Читать пост</a></p>
                   {% if not forloop.last %}
                   <hr>
                   {% endif %}
         </li>
         {% endif %}
         {% endfor %}
</ul>

Здесь p.id – это уникальный идентификатор статьи (мы его прописывали в коллекции data_db). При переходе на главную страницу под каждой статьей увидим ссылку:

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

urlpatterns = [
    path('', views.index, name='home'),
    path('about/', views.about, name='about'),
    path('cats/<int:cat_id>/', views.categories, name='cats_id'),
    path('cats/<slug:cat_slug>/', views.categories_by_slug, name='cats'),
    path('archive/<year4:year>/', views.archive, name='archive'),
]

Давайте здесь опишем три следующих маршрута:

urlpatterns = [
    path('', views.index, name='home'),
    path('about/', views.about, name='about'),
    path('post/<int:post_id>/', views.show_post, name='post'),
]

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

Добавим функцию представления show_post в модуль views.py приложения women, а другие не нужные функции удалим:

def show_post(request, post_id):
    return HttpResponse(f"Отображение статьи с id = {post_id}")

После этого перейдем в шаблон index.html и в нем сформируем URL-адреса для каждой статьи с помощью специального шаблонного тега url, который подробно описан на странице документации:

https://docs.djangoproject.com/en/4.2/ref/templates/builtins/

В частности, в шаблоне index.html нам нужно прописать следующее:

<p ><a href="{% url 'post' p.id %}">Читать пост</a></p>

То есть, после тега url указывается имя маршрута ‘post’, а затем, через пробел аргумент p.id для формирования этого маршрута. Почему именно так? На самом деле тег url работает аналогично известной нам функции reverse. Если мы ее запишем в виде:

reverse('post', args=(11, ))      # '/post/11/'

то получим маршрут '/post/11/'. И тот же эффект получаем от применения тега url:

{% url 'post' 11 %}

Как видите, это гораздо более удобное решение для формирования URL-адресов. Если в будущем маршруты в файле urls.py изменятся, то изменения автоматически произойдут и в шаблоне. Ничего дополнительно редактировать не придется. В этом основное удобство использования шаблонного тега url.

Давайте в заключение добавим ссылки для главного меню сайта и отобразим его в HTML-документе. Вначале в файле urls.py мы пропишем следующие маршруты:

urlpatterns = [
    path('', views.index, name='home'),
    path('about/', views.about, name='about'),
    path('addpage/', views.addpage, name='add_page'),
    path('contact/', views.contact, name='contact'),
    path('login/', views.login, name='login'),
    path('post/<int:post_id>/', views.show_post, name='post'),
]

А коллекцию menu изменим, добавив в нее информацию об именах маршрутов (в файле views.py):

menu = [{'title': "О сайте", 'url_name': 'about'},
        {'title': "Добавить статью", 'url_name': 'add_page'},
        {'title': "Обратная связь", 'url_name': 'contact'},
        {'title': "Войти", 'url_name': 'login'}
]

Также здесь сразу пропишем функции-заглушки для каждого пункта меню:

def addpage(request):
    return HttpResponse("Добавление статьи")
 
def contact(request):
    return HttpResponse("Обратная связь")
 
def login(request):
    return HttpResponse("Авторизация")

Осталось в файле index.html выполнить отображение меню. Я сделаю это следующим образом:

<ul>
<li><a href="{% url 'home' %}">Главная</a></li>
{% for m in menu %}
{% if not forloop.last %}<li>{% else %}<li class="last">{% endif %}
         <a href="{% url m.url_name %}">{{m.title}}</a>
</li>
{% endfor %}
</ul>

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

Курс по Django: https://stepik.org/a/183363

Видео по теме