# Часть четвёртая. Шаблон сайта

**Цель:** Создание полноценного сайта с простых шаблонов

**Задачи:**

* Создание простых страниц на HTML
* Изменение ссылок внутри проекта
* Введение динамических и статических элементов страницы

## Создаём html-страницы

В этой части курса мы научимся выводить полноценные html-страницы. Так как, мы хотим создать шаблон страниц, а не просто одну страницу, мы должны прибегнуть к полноценной вёрстке на Python. Для этого, в папке нашего приложения blog, нужно создать папку templates. Название папки зарезервировано плагином Django, так как Django каждый раз собирает наши файлы и с нуля отрисовывает страницу. При сборке сайта, джанго обращается к папкам и файлам с конкретными названиями.

![Папка "blog"](/files/-MNxwx7S4rELt6TuSAyG)

Теперь, в папке templates, нам нужно создать ещё одну папку, которая точно также называется, как и приложение, то есть в нашем случае – blog.

Почему именно так? Дело в том, что Django собирает все папки в единую папку templates. Сейчас у нас одно приложение – blog, но если бы у нас было бы ещё несколько приложений, то в папке templates был бы хаос из файлов. Несмотря на то, что у нас одно приложение, мы будем писать сайт с правилами хорошего тона в программировании.

Теперь в папке blog, создадим файлы home.html и contacts.html

![](/files/-MNxwx7bel7J96HOUN14)

Как мы видим, файлы у нас не пусты.

```markup
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>

    </body>
</html>
```

Удалим всё лишнее.

Настроим PyCharm. Нам потребуется плагин для работы с html-файлами. Плагин называется – Emmet.

Переходим в IDE по следующей ветке: File -> Settings

![](/files/-MNxwx7aSaiQjFemHFZR)

В панели поиска напишем название нашего плагина

![](/files/-MNxwx7NgNJ_j5nwp5ip)

![](/files/-MNxwx7U1mRdI60XU2r6)

Обычно, он установлен по умолчанию и находится во вкладке Editor. Если его у вас нет, нажмите кнопку Install в появляющемся после запроса окне.

Как мы видим, плагин будет реагировать на кнопку “Tab”. Это нам и нужно. Нажимаем ОК и возвращаемся к файлам html.

Введите `!` и нажмите Tab.

![Весь текст набрался самостоятельно](/files/-MNxwx7fPgpA1X_bobVL)

Не меняем ничего, кроме двух пунктов.

1. Удалим в поле `<title>` слово “Documents”
2. В теле введём заголовок `<h2>`

Результат (contacts.html):

```markup
<!doctype html>  
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title></title>
    </head>
    <body>
        <h2>Контакты работают иначе</h2>
    </body>
</html>
```

Теперь, чтобы шаблоны были доступны, необходимо в главном файле настройки проекта – settings.py в установленных приложениях (INSTALLED\_APPS) ввести наше приложение – blog.

Сделаем тоже самое для главной страницы.

Результат (home.html):

```markup
<!doctype html>  
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title></title>
    </head>
    <body>
        <h2>Ура! Главная страница поменялась</h2>
    </body>
</html>
```

Переходим к файлу настроек и вписываем туда строку:

`blog.apps.BlogConfig`

Таким образом, мы вводим приложение blog, сведения о котором хранятся в файле apps и обращаемся к функции BlogConfig.

Результат:

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

Взглянем на файл apps.py в проекте сайта.

```python
from django.apps import AppConfig  


class BlogConfig(AppConfig):
    name = 'blog'
```

Остался последний шаг – настроить vievs.py. Сейчас там прописаны функции – HttpResponse, то есть ответы через http. Это неправильно. Сайт будет работать на html вёрстке и нам нужно не выдавать http ответы, а обращаться к html шаблонам. Исправляем:

```python
from django.shortcuts import render  
from django.http import HttpResponse  


def home(request):  
    return render(request, 'blog/home.html')  


def contacts(request):  
    return render(request, 'blog/contacts.html')
```

Обратите внимание на сигналы PyCharm:

![](/files/-MNxwx7LJY0zWOHGxaNU)

Строка с импортом библиотеки HttpResponse стала серой. Это знак того, что мы не использовали в фале программы эту библиотеку. Её можно удалить.

Помимо прочего, появилось зелёные ярлычки слева. Это знак, что мы обращаемся к нашему html-файлу. Если навести на него курсор, отобразиться имя файла, а если кликнуть по нему, мы перейдём в этот файл.

![](/files/-MNxwx7Q8z9JuQ4wawnH)

Запускаем сервер и проверяем как всё работает:

![](/files/-MNxwx7YJSVCyvYQJqUe)

![](/files/-MNxwx7_ayr36THLuwW9)

Всё работает как надо!

## Создаём html-страницы с динамическими данными

Теперь научимся передавать динамические данные. Это – заготовка под базы данных, которыми мы потом будем пользоваться.

Перейдём в файл views.py.

Написав немного кода, я изменил файл так:

```python
from django.shortcuts import render  

news = [
    {
        'title': 'Первая запись',  
        'text': 'Много-много текста',  
        'date': '10 Мая 2020',  
        'author': 'Валерий'  
    },  
    {  
        'title': 'Вторая запись',  
        'text': 'Снова много-много текста',  
        'date': '19 Мая 2020',  
        'author': 'Егор'  
    }  
]  


def home(request):  
    data = {  
        'news': news,  
        'title': 'Главная страница'  
    }  
    return render(request, 'blog/home.html', data)  


def contacts(request):  
    return render(request, 'blog/contacts.html')
```

Построчно разберём что к чему. Создан список news, состоящий из 2 записей. Каждая запись – это словарь. В каждом словаре по 4 элемента. В функции отрисовки главной страницы, я добавил переменную data, которая создаёт словарь news и вызывает в него созданный список новостей. Плюс к этому, в data мы вызывает ещё один объект – заголовок страницы (title). В самом же рендере, мы добавили переменную в конце и вызываем её.

Теперь перейдём в html-файл нашей главной страницы (home.html)

Снова написав немного кода, получаем следующее:

```markup
<!doctype html>  
<html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">  
        <title>{{ title }}</title>  
    </head>
    <body>  
        {% for post in news %}  
            <h1>{{ post.title }}</h1>  
            <p>{{ post.text }}</p>  
            {% if post.author == 'Валерий' %}  
                <p>Автор: Админ</p>  
            {% else %}  
                <p>Автор: {{ post.author }}</p>  
            {% endif %}  
            <p>Дата: {{ post.date }}</p>  
        {% endfor %}  
    </body>  
</html>
```

В поле \ мы вызываем нужную нам строку – «Главная страница». В теле мы используем 2 конструкции:

1. for
2. if

Так как, мы пишем вёрстку на Python в html-файле, конструкции используются при помощи такой конфигурации: `{% %}`

Если бы мы писали тот же код, но на чистом питоне, выглядел бы он так:

```python
for post in news:
    print('post.title')
    print('post.text')
    if post.author == 'Валерий':
        print('Автор: Админ')
    else:
        print('Автор: ', post.author)
    print('Дата: ', post.data)
```

Посмотрите основные отличия:

* Отсутствие двоеточий после for и if, но наличие конструкции endfor и endif
* Добавлена разметка html, то есть \<p>, \<h2> и т.п.
* Отсутствие кавычек и слова "print"

Запустим сервер и посмотрим на результат:

![](/files/-MNxwx7gDh4SgfdwCqMj)

Подредактируем ещё немного файл views.py. Допустим, нам нужно вывести только заголовок (title), а остаток кода не менять и не выводить все новости (data). В таком случае, сделаем следующую конструкцию:

```python
def contacts(request):  
    return render(request, 'blog/contacts.html', {'title': 'Страничка про МИИГАиК'})
```

А в файл contacts.html выглядит теперь так:

```markup
<!doctype html>  
<html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">  
        <title>{{ title }}</title>  
    </head>
    <body>
        <h2>Контакты работают иначе</h2>
    </body>  
</html>
```

Проверяем:

![](/files/-MNxwx7Z1okcYpEHxzid)

Теперь давайте сравним 2 файла home.html и contacts.html. Что в них отличается?

Единственный блок, который у них отличается – тело, а «шапка» (верхняя часть сайта) и «подвал» (нижняя часть сайта) остаются одинаковыми. Конечно, нам не будет интересно переписывать один и тот же код на каждой странице. Давайте исправим это неудобство.

Создадим рядом с файлами home.html и contacts.html файл main.html и пишем в него следующий код:

```markup
<!doctype html>  
<html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">  
        <title>{{ title }}</title>  
    </head>
    <body>  
        {% block main_section %}  
        {% endblock %}  
    </body>  
</html>
```

То есть, мы можем скопировать весь код с любого из html-файла и в теле сайта записать блочную конструкцию:

```markup
{% block main_section %}  
{% endblock %}
```

Перейдём в файл contacts.html и перепишем его таким образом:

```markup
{% extends 'blog/main.html' %}  
{% block main_section %}  
    <h2>Контакты работают иначе</h2>  
{% endblock main_section %}
```

То есть, мы обращаемся к файлу blog/main.html и из него берём всё, что было до блока, пишем блок (тело страницы) и забираем всё, что нужно после. Повторяем операцию с файлом home.html.

```markup
{% extends 'blog/main.html' %}  
{% block main_section %}  
    {% for post in news %}  
        <h1>{{ post.title }}</h1>  
        <p>{{ post.text }}</p>  
        {% if post.author == 'Валерий' %}  
            <p>Автор: Админ</p>  
        {% else %}  
            <p>Автор: {{ post.author }}</p>  
        {% endif %}  
    <p>Дата: {{ post.date }}</p>  
    {% endfor %}  
{% endblock main_section %}
```

Проверяем и видим тоже самое. Давайте теперь напишем какую-нибудь глобальную фразу в main.html. Например, так:

```markup
<!doctype html>  
<html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">  
        <title>{{ title }}</title>  
    </head>
    <body>  
        <h1>МИИГАиК - лучший ВУЗ!</h1>
        {% block main_section %}  
        {% endblock %}  
    </body>  
</html>
```

Проверим что получилось:

![](/files/-MNxwx7cwm4ul5_zWAM9)

![](/files/-MNxwx7V1l4wTPnp3WpW)

Теперь эта фраза нас преследует везде и на каждой странице. Сейчас это изменение можно убрать, так как нам ещё предстоит много работы со станицами.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://valerylinkov2504.gitbook.io/sitepython/4.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
