Руководство часть 5: Создание домашней страницы
===============================================

* Назад
* Обзор: Django
* Далее

Теперь мы готовы создать код нашей первой страницы — домашняя страница сайта LocalLibrary будет показывать количество записей в каждой модели, кроме того, она будет выводить боковую навигационную панель с ссылками на другие страницы сайта. В результате мы приобретём практический навык написания простых URL-преобразований и отображений, получения записей из базы данных и применения шаблонов.

| Требования: | Прочитать Введение в Django. Завершить изучение предыдущих частей руководства (включая Руководство часть 4: Django административный раздел сайта). |
| --- | --- |
| Цель: | Понимать как создавать простые url-преобразования (которые не содержат никаких данных) и отображения, как получать данные из моделей и создавать шаблоны. |

Обзор
-----

Теперь, когда мы определили наши модели и создали несколько записей в них, пришло время написать код, который будет показывать данную информацию пользователям. И первое, что нам необходимо сделать это определиться какую информацию мы бы хотели показывать на наших страницах, а затем определить соответствующие URL-адреса для получения соответствующих ресурсов. Затем нам надо создать url-преобразования, отображения (функции, или классы), а затем шаблоны страницы.

Диаграмма, представленная ниже, демонстрирует главный поток данных и элементов, которые нужно реализовать для управления HTTP запросами и ответами. Поскольку мы уже создали модель, то нам остаётся создать следующее:

* URL-преобразования для перехода по соответствующему URL-адресу (с учётом информации, передаваемой в данном адресе) к соответствующей функции отображения.
* Функции отображения для запроса соответствующих данных из моделей, создание страниц HTML для показа этих данных и их отправку в клиент пользователя (в браузер).
* Шаблоны, которые используются отображениями для рендеринга (отрисовки) данных.

![](/ru/docs/Learn/Server-side/Django/Home_page/basic-django.png)

Как вы увидите в следующем разделе, у нас будет 5 страниц, которые мы немного опишем в данной статье. Данная статья, большей частью, будет сконцентрирована на реализации всего-лишь одной, домашней страницы нашего сайта (к другим страницам мы перейдём в других частях руководства). Это должно дать вам хорошее базовое представление о работе с URL-преобразованиями (связывании), отображениями и моделями.

Определяем URL-адреса страниц
-----------------------------

По сути, так как для конечных пользователей, данная версия сайта *LocalLibrary* является read-only (только для чтения), то нам надо создать домашнюю страницу и страницы, которые будут *показывать* списки авторов и книг, а также детальную информацию о них, соответственно.

Перечислим URL-адреса, которые понадобятся для наших страниц:

* `catalog/` — Домашняя/индексная страница.
* `catalog/books/` — Список всех книг.
* `catalog/authors/` — Список всех авторов.
* `catalog/book/<id>` — Детальная информация для определённой книги со значением первичного ключа равного `<id>`. Например, `/catalog/book/3`, для `id = 3`.
* `catalog/author/<id>` — Детальная информация для определённого автора со значением первичного ключа равного `<id>`. Например, `/catalog/author/11`, для автора с `id = 11`.

Первые три URL-адреса используются для показа домашней страницы, а также списков книг и авторов. Они не кодируют никакой дополнительной информации и результат показа данных страниц будет полностью зависеть от того, что находится в базе данных и, по сути, будет все время одним и тем же (при неизменной базе данных, конечно).

Последние два URL-адреса применяются для показа детальной информации об определённой книге, или авторе — в себе они содержат соответствующее значение идентификатора (показан как `<id>`, выше). URL-преобразование получает данную информацию и передаёт её в отображение, которое применяет её для запроса к базе данных. Для кодирования и применения данной информации в вашем URL-адресе нам понадобится только одно url-преобразование, соответствующее отображение и шаблон страницы для показа любой книги (или автора).

**Примечание:** Django позволяет вам конструировать ваши URL-адреса любым, удобным для вас, способом — вы можете закодировать информацию в теле URL-адреса, как показано выше, или использовать URL-адрес типа `GET` (например, `/book/?id=6`). Независимо от ваших предпочтений, URL-адреса должны быть понятными, логичными и читабельными (посмотрите совет W3C здесь).

Документация Django рекомендует кодировать информацию в теле URL-адреса, на практике это приводит к лучшей структуре сайта.

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

Создание главной страницы сайта
-------------------------------

Первой страницей, которую мы создадим, будет главная страница сайта (`catalog/`). Она будет небольшой статической HTML-страницей, которая будет показывать вычисленные "количества" различных записей из базы данных. Для того, чтобы проделать данную работу мы вначале создадим URL-преобразование, затем отображение и шаблон.

**Примечание:** Лучше уделить больше внимания на данный раздел, поскольку информация, представленная здесь, применяется для создания всех страниц сайта.

### URL-преобразование

Когда мы создавали скелет сайта мы обновили **locallibrary/urls.py** так что всякий раз, когда начинается URL-адрес наш catalog/ получен и URLConf catalog.urls подключён для обработки оставшейся части строки.
```

urlpatterns += [
    path('catalog/', include('catalog.urls')),
]
```


Примечание: всякий раз, когда Django сталкивается c `django.urls.include()` он отбрасывает часть совпавшего URL , и отправляет оставшуюся строку в включённый URLconf для дальнейшей обработки.

Внутри нашего каталога приложения откройте **urls.py** и поместите в него текст, отмеченный жирным, ниже.


```python
urlpatterns = [
    path('', views.index, name='index'),
]
```


Эта функция `path()` определяет URL-паттерн (в данном случае это пустая строка: `'' -` мы поговорим чуть более подробно о них далее в данном руководстве) и функцию отображения, которая будет вызвана, если введённый адрес будет соответствует данному паттерну (`views.index` — это функция с именем `index()` в **views.py**).

Данная функция `path()`, кроме того, определяет параметр `name`, который уникально определяет *это* частное URL-преобразование. Вы можете использовать данное имя для "обратного" ("reverse") преобразования — то есть, для динамического создания URL-адреса, указывающего на ресурс, на которое указывает данное преобразование. Например, теперь, когда у нас имеется данное символическое имя, мы можем ссылаться на нашу домашнюю страницу при помощи создания следующей ссылки внутри какого-либо шаблона:


```html
<a href="{% url 'index' %}">Home</a>.
```


**Примечание:** Мы могли бы, конечно, жёстко указать прямую ссылку (то есть, `<a href="/catalog/">Home</a>`), но тогда, если мы изменим адрес нашей домашней страницы (например на `/catalog/index`), то данные ссылки перестанут корректно работать. Применение "обратного" url-преобразования более гибкий и эффективный подход!

### Отображения (на основе функций)

Отображение является функцией, которая обрабатывает HTTP-запрос, получает данные из базы данных (при необходимости), которые применяются для генерации страницы HTML. Затем функция отображения возвращает сгенерированную страницу пользователю в виде HTTP-ответа. В нашем случае, индексная функция демонстрирует этот процесс — она получает информацию о количестве записей `Book`, `BookInstance`, доступности `BookInstance`, а также записи `Author` из базы данных, затем передаёт эти записи в шаблон страницы, генерирует страницу и передаёт её пользователю (клиенту пользователя, например браузеру).

Откройте **catalog/views.py** и отметьте для себя, что данный файл уже импортирует функцию render() - функцию, которая генерирует HTML-файлы при помощи шаблонов страниц и соответствующих данных.


```python
from django.shortcuts import render

# Создайте ваше отображение здесь
```


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


```python
from .models import Book, Author, BookInstance, Genre

def index(request):
    """
 Функция отображения для домашней страницы сайта.
 """
    # Генерация "количеств" некоторых главных объектов
    num_books=Book.objects.all().count()
    num_instances=BookInstance.objects.all().count()
    # Доступные книги (статус = 'a')
    num_instances_available=BookInstance.objects.filter(status__exact='a').count()
    num_authors=Author.objects.count()  # Метод 'all()' применён по умолчанию.

    # Отрисовка HTML-шаблона index.html с данными внутри
    # переменной контекста context
    return render(
        request,
        'index.html',
        context={'num\_books':num_books,'num\_instances':num_instances,'num\_instances\_available':num_instances_available,'num\_authors':num_authors},
    )
```


Первая часть функции отображения получает количество записей при помощи вызова функции `objects.all()` у атрибута `objects`, доступного для всех классов моделей. Похожим образом мы получаем список объектов `BookInstance`, которые имеют статус 'a' (Доступно). Вы можете найти дополнительную информацию о работе с моделями в предыдущей части руководства (Руководство часть 3: Применение моделей > Поиск записей).

В конце функции `index` вызывается функция `render()`, которая, в качестве ответа, создаёт и возвращает страницу HTML (эта функция "оборачивает" вызовы нескольких функций, тем самым существенно упрощая процесс разработки). В качестве параметров ей передаются объект `request` (типа `HttpRequest`), шаблон HTML-страницы с метками (`placeholders`), которые будут замещены данными, а также переменной `context` (словарь Python, который содержит данные, которые и будут замещать метки в шаблоне).

В следующем разделе мы более подробно поговорим о шаблонах и переменной контекста. Давайте создадим наш шаблон, чтобы показать уже что-нибудь пользователю!

### Шаблон

Шаблон это текстовый файл, который определяет структуру и расположение данных в файле, кроме того, в нем размещают специальные метки (placeholders), которые используются для показа реального содержимого, то есть данных. По умолчанию Django ищет файлы шаблонов в директории с именем '**templates**' внутри вашего приложения. Например, внутри индексной функции отображения, которую мы только что создали, вызов `render()` будет пытаться найти файл **/locallibrary/catalog/templates/*index.html*** и в случае неудачи сгенерирует ошибку о том, что файл не найден. Вы можете увидеть данную ошибку, если вы сохраните предыдущие изменения, затем перейдёте в браузер и наберёте в адресной строке `127.0.0.1:8000`. В результате, в окно браузера будет выведено сообщение об ошибке "TemplateDoesNotExist at /catalog/" и некоторая другая информация.

**Примечание:** На самом деле, в зависимости от настроек проекта, Django просматривает несколько мест в поисках шаблона (поиск в директории приложения осуществляется по умолчанию!). Вы можете найти больше информации о шаблонах и форматах, которые они поддерживают, перейдя по ссылке Шаблоны (Django docs).

#### Расширение шаблонов

Шаблон главной страницы нашего сайта должен соответствовать стандарту разметки HTML для разделов `head` и `body`, кроме того иметь разделы для навигации (на другие страницы, которые мы создадим позже) и показа некоторого вводного текста. Большая часть данной структуры будет одинаковой для всех страниц нашего сайта. Таким образом, чтобы избежать копирования одной и той же информации, язык создания шаблонов Django позволяет вам объявить базовый шаблон, а затем расширить его, замещая только те части, которые являются специфическими для каждой страницы.

Например, базовый шаблон **base\_generic.html** может выглядеть как показано ниже. Как вы видите, этот файл содержит некоторую "общую" структуру HTML, разделы для заголовка, панель навигации и содержимое, отмеченное тэгами шаблона `block` и `endblock` (показано жирным). Данные блоки могут быть пустыми, или иметь содержимое, которое будет использоваться "по умолчанию" всеми страницами-наследниками.

**Примечание:** *Тэги* шаблона подобны функциям, которые могут применяться для создания циклов по спискам, выполнять условные операции и так далее. Кроме тэгов, язык шаблона позволяет использовать переменные (которые передаются в шаблон из отображения), а также *шаблонные фильтры*, которые переформатируют переменные (например, переводят строку в нижний регистр).


```django
<!doctype html>
<html lang="en">
<head>
  {% block title %}<title>Local Library</title>{% endblock %}
</head>

<body>
  {% block sidebar %}<!-- insert default navigation text for every page -->{% endblock %}
  {% block content %}<!-- default content text (typically empty) -->{% endblock %}
</body>
</html>
```


Когда мы определяем шаблон для конкретного отображения, то в первую очередь мы объявляем базовый шаблон (при помощи тэга `extends` — смотрите код в следующем фрагменте). Если имеются блоки в базовом шаблоне, которые мы хотим заместить, тогда в нашем текущем шаблоне мы объявляем `block`/`endblock` и указываем соответствующее имя блока.

Например фрагмент кода, показанный ниже, демонстрирует применение тэга `extends` и переопределяет блок с именем `content`. Окончательный код HTML будет содержать все структуры базового файла шаблона (включая содержимое по умолчанию, которое мы указали в блоке `title`) и код блока `content`, который мы разместили в текущем файле шаблона.


```django
{% extends "base\_generic.html" %}

{% block content %}
  <h1>Local Library Home</h1>
  <p>
    Welcome to <em>LocalLibrary</em>, a very basic Django website developed as a
    tutorial example on the Mozilla Developer Network.
  </p>
{% endblock %}
```


#### Базовый шаблон сайта LocalLibrary

Базовый шаблон, который мы планируем использовать для сайта *LocalLibrary*, представлен ниже. Как вы видите, данный фрагмент содержит HTML код и объявляет следующие блоки `title`, `sidebar` и `content`. Мы добавили заголовок по умолчанию (который, возможно, мы захотим изменить), а также боковую панель навигации, содержащей ссылки на списки всех книг и авторов (панель навигации, мы, вероятно, не будем менять/замещать, но, тем не менее, добавив этот блок, мы оставим для себя такую возможность).

**Примечание:** Во фрагменте мы используем два дополнительных шаблонных тега: `url` и `load static`. Они будут описаны в следующих разделах.

Создайте новый файл — **/locallibrary/catalog/templates/*base\_generic.html*** — и добавьте в него следующее содержимое:


```django
<!doctype html>
<html lang="en">
  <head>
    {% block title %}<title>Local Library</title>{% endblock %}
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
 rel="stylesheet"
 href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

    <!-- Добавление дополнительного статического CSS файла -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/styles.css' %}" />
  </head>

  <body>
    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-2">
          {% block sidebar %}
            <ul class="sidebar-nav">
              <li><a href="{% url 'index' %}">Home</a></li>
              <li><a href="">All books</a></li>
              <li><a href="">All authors</a></li>
            </ul>
          {% endblock %}
        </div>
        <div class="col-sm-10 ">{% block content %}{% endblock %}</div>
      </div>
    </div>
  </body>
</html>
```


Шаблон использует (и включает в себя) JavaScript и CSS от Bootstrap для лучшего размещения элементов и формирования внешнего вида HTML страницы. Применение Bootstrap, или любого другого фреймворка для клиентской части сайта, является довольно продуктивным способом повышения привлекательности страницы, в том числе, это учитывает возможность запроса и показа сайта с устройств, с различными разрешениями экрана, а кроме того, это позволяет нам повысить уровень взаимодействия с пользователем — мы направим большую часть своих усилий на серверную часть нашего сайта!

Базовый шаблон ссылается на локальный файл css (**styles.css**), который предоставляет дополнительные стили. Создайте **/locallibrary/catalog/static/css/styles.css** и добавьте в него следующее содержимое:


```css
.sidebar-nav {
  margin-top: 20px;
  padding: 0;
  list-style: none;
}
```


#### Индексный шаблон (шаблон главной страницы сайта)

Создайте файл HTML **/locallibrary/catalog/templates/*index.html*** и скопируйте в него код, указанный ниже. Как вы наверное заметили, в первой строке мы расширяем наш базовый шаблон, а затем замещаем содержимое блока `content`, базового шаблона, новым содержимым текущего шаблона.


```django
{% extends "base\_generic.html" %}

{% block content %}
<h1>Local Library Home</h1>

  <p>Welcome to <em>LocalLibrary</em>, a very basic Django website developed as a tutorial example on the Mozilla Developer Network.</p>

<h2>Dynamic content</h2>

  <p>The library has the following record counts:</p>
  <ul>
    <li><strong>Books:</strong> {{ num\_books }}</li>
    <li><strong>Copies:</strong> {{ num\_instances }}</li>
    <li><strong>Copies available:</strong> {{ num\_instances\_available }}</li>
    <li><strong>Authors:</strong> {{ num\_authors }}</li>
  </ul>

{% endblock %}
```


В данном фрагменте, в разделе *Динамическое содержимое,* мы объявили метки (*шаблонные переменные*) для информации, которую мы получаем из соответствующего отображения. Данные переменные объявляются при помощи "двойных фигурных скобок" (в предыдущем фрагменте выделено жирным).

**Примечание:** Переменные шаблона заключаются в двойные фигурные скобки (`{{ num_books }}`) , а тэги шаблона (функции шаблона), помещаются в одинарные фигурные скобки со знаками процента (`{% extends "base_generic.html" %}`).

Важно отметить, что данные переменные имеют имена, соответствующие именам передаваемых *ключей* из словаря переменной `context`, которая, в свою очередь, передаётся из отображения, во время вызова функции `render()` (смотри ниже). При отрисовке шаблона, вместо этих ключей будут подставлены, соответствующие им, *значения*.


```python
return render(
    request,
    'index.html',
     context={'num\_books':num_books,'num\_instances':num_instances,'num\_instances\_available':num_instances_available,'num\_authors':num_authors},
)
```


#### Ссылка на статические файлы их шаблонов

Любой ваш проект с большой вероятностью будет использовать статические ресурсы, включая JavaScript, CSS и изображения. В связи с тем, что расположение этих файлов может быть неизвестно (или может измениться), Django позволяет вам в шаблоне указать относительное расположение данных файлов при помощи глобального значения `STATIC_URL` (по умолчанию, значение параметра `STATIC_URL` установлено в '`/static/`', но вы можете выбрать любое другое значение, указав, например, сетевой ресурс, или что-то ещё).

Внутри шаблона вы вызываете функцию (тэг) `load`, которая загружает статическую библиотеку "static" (как показано ниже). После того как статическая библиотека загружена, вы можете использовать тэг шаблона `static`, который указывает относительный путь URL к интересующему вас файлу.


```django
<!-- Добавляем дополнительный статический CSS-файл -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}" />
```


Тем же способом вы можете загрузить нужное изображение. Например:


```django
{% load static %}
<img
 src="{% static 'catalog/images/local\_library\_model\_uml.png' %}"
 alt="My image"
 style="width:555px;height:540px;" />
```


**Примечание:** Фрагменты выше указывают пути расположения файлов, но Django не использует их по умолчанию. В процессе разработки сервер использует значения, указанные в глобальном файле URL-преобразований (**/locallibrary/locallibrary/urls.py**), который мы создали в части создание скелета сайта. В дальнейшем, в продакшене, вам нужно будет уточнить параметры расположения статических файлов. Мы вернёмся к этому позже.

Для получения более подробной информации о работе со статическими файлами обратитесь к документации по ссылке Управление статическими файлами (Django docs).

#### Построение URL-адресов

Базовый шаблон, указанный выше, вводит тэг `url`.


```python
<li><a href="{% url 'index' %}">Home</a></li>
```


Данный тэг с именем `url()`, ищет в файле **urls.py** связанное значение переменной, указанной в качестве её параметра `'index'`, а затем возвращает URL, который вы можете использовать для ссылки на соответствующие ресурсы.

Как теперь все это выглядит?
----------------------------

На данный момент мы должны были сделать всё что необходимо, для того, чтобы показать главную страницу нашего сайта. Запустите сервер (`python3 manage.py runserver`) и введите в ваш браузер адрес `http://127.0.0.1:8000/`. Если все настроено как надо, то ваш сайт должен выглядеть как показано на следующей картинке.

![Index page for LocalLibrary website](/ru/docs/Learn/Server-side/Django/Home_page/index_page_ok.png)

**Примечание:** На данном этапе вы не сможете воспользоваться ссылками на страницы **All books** и **All authors**, потому что url-адреса, отображения и шаблоны для данных страниц не созданы (мы просто объявили метки для соответствующих ссылок в базовом шаблоне `base_generic.html`).

Проверьте себя
--------------

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

1. В главном файле шаблона (*base\_generic.html*) есть блок `title`. Переопределите этот блок в индексном шаблоне (*index.html*) и задайте новый заголовок для этой страницы.
2. Модифицируйте функцию отображения таким образом, чтобы получать из базы данных количество жанров и количество книг, которые содержат в своих заголовках какое-либо слово (без учёта регистра), а затем передайте эти значения в шаблон.
Итог
----

Мы создали домашнюю страницу для нашего сайта — HTML страница, которая показывает количество некоторых записей из базы данных и содержит ссылки на другие "все-ещё-будут-созданы" страницы. Кроме того, мы изучили большое количество базовой информации об url-преобразованиях, отображениях, запросах к базе данных, используя наши модели, передачу информации из отображений в шаблоны, кроме того, создание и расширение шаблонов.

В следующей части, при помощи наших новых знаний, мы создадим ещё четыре страницы.

Смотрите также
--------------

* Написание вашего первого приложения Django, часть 3: Отображения и Шаблоны (Django docs)
* URL-диспетчер (Django docs)
* Функции отображения (DJango docs)
* Шаблоны (Django docs)
* Управление статическими файлами (Django docs)
* Удобные (встроенные) функции Django (Django docs)
* Назад
* Обзор: Django
* Далее