Attention! Чтобы следить за ходом лекции нужно работать с данной версией репозитория
Познакомимся поподробнее с шаблонами.
Первое дело: тэг {% include %}
В наших шаблонах присутствует повторяющийся HTML. Это например контейнер <head>
, подключение обертка (wrapper) вокруг контента, footer.
Философия Django утверждает, что ничто не должно повторяться и быть неудобным.
Поэтому существует простой инструмент для того, чтобы исправить ситуацию.
Создадим в communities/templates
шаблон base.html
и поместим туда скелет любой нашей страницы.
<!DOCTYPE html>
<html lang="ru">
<head>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<title></title>
<meta name="description" content="">
</head>
<body>
<header>
<div class="container">
</div>
</header>
<div>
<div class="container">
<div id="messages">
</div>
<div class="content">
</div>
</div>
</div>
<footer class="push">
<div class="container">
</div>
</footer>
</body>
</html>
Сразу подключаем jquery. Именно в контейнере head мы будем подключать все внешние скрипты, таблицы стилей. Там же мы указываем необходимое для опознания нашего сайта поисковыми системами: title и description - имя и описание страницы.
Этот код будет скелетом. Мы должны указать куда в нём будет "подставляться" контент определенной страницы.
<!DOCTYPE html>
<html lang="ru">
<head>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<title>{% block title %}{% endblock %}</title>
<meta name="description" content="{% block description %}{% endblock %}">
</head>
<body>
<header>
<div class="container navbar">
</div>
</header>
<div>
<div class="container">
<div id="messages">
</div>
<div class="content">
{% block content %}{% endblock %}
</div>
</div>
</div>
<footer class="push">
<div class="container">
</div>
</footer>
</body>
</html>
Далее откроем наш существующий шаблон community_list.html и изменим его на следующее.
{% extends "base.html" %}
{% block title %}MAI COMMUNITIES{% endblock %}
{% block description %}
Curated list of MAI student communities.
{% endblock %}
{% block content %}
<div class="communities-list">
{% for community in community_list %}
<div class="community">
<br/>
<h3><a href="{% url 'communities:community_detail' community.pk %}">{{ community.title }}</a></h3>
<p>{{ community.description }}</p>
<p><a href="{{ community.vk_link }}">{{ community.vk_link }}</a></p>
<p>{{ community.contacts }}</p>
<br/>
</div>
{% endfor %}
</div>
{% if community_list.paginator.num_pages > 1 %}
<div class="pagination">
{% if community_list.has_previous %}
<a href="?page={{ community_list.previous_page_number }}">←</a>
{% endif %}
{% for num in community_list.paginator.page_range %}
{% if num == community_list.number %}
<span class="current"><b>{{ num }}</b></span>
{% else %}
<a href="?page={{ num }}"> {{ num }}</a>
{% endif %}
{% endfor %}
{% if community_list.has_next %}
<a href="?page={{ community_list.next_page_number }}">→</a>
{% endif %}
</div>
{% endif %}
{% endblock %}
Итак, что произойдет, если Django в ответ на запрос пользователя "отрисует" шаблон community_list.html?
- Из-за тэга extends за основу будет взят указанный шаблон ("base.html").
- Блоки основного шаблона (title, description, content) буду заполнены содержимым из шаблона community_list.
Например в тэг
<title>
в контейнере<head>
будет записана строка "MAI COMMUNITIES".
Это дает нам определенные плюсы: мы не переписываем HTML код и в каждом шаблоне определяем только какой будет выводиться контент.
Однако это не всё. Сейчас код отрисовки одного сообщества в community_list и в community_detail совпадает. Совпадает значит повторяется. Это плохо.
Нам было бы удобно вынести его в отдельный шаблон, чтобы мы могли подавать ему на вход объект community и получать отрисовку одного сообщества. Плюс такого решения в том, что мы могли бы использовать один и тот же шаблон несколько раз в разных местах не переписывая его. К тому же так просто красивее. Так же стоит поступать с пагинацией - вынести её в отдельный шаблон.
В этом нам поможет тэг {% include %}
.
Создадим новый шаблон community_card.html
<div class="community-card">
<h3><a href="{% url 'communities:community_detail' community.pk %}">{{ com.title }}</a></h3>
<p>{{ com.description }}</p>
<p><a href="{{ com.vk_link }}">{{ com.vk_link }}</a></p>
<p>{{ com.contacts }}</p>
</div>
Да, это весь код, который должен в нём содержаться.
Теперь изменим community_list.html
{% extends "base.html" %}
{% block title %}MAI COMMUNITIES{% endblock %}
{% block description %}
Curated list of MAI student communities.
{% endblock %}
{% block content %}
<div class="communities-list">
{% for community in community_list %}
{% include "community_card.html" with com=community %}
{% endfor %}
</div>
{% if community_list.paginator.num_pages > 1 %}
<div class="pagination">
{% if community_list.has_previous %}
<a href="?page={{ community_list.previous_page_number }}">←</a>
{% endif %}
{% for num in community_list.paginator.page_range %}
{% if num == community_list.number %}
<span class="current"><b>{{ num }}</b></span>
{% else %}
<a href="?page={{ num }}"> {{ num }}</a>
{% endif %}
{% endfor %}
{% if community_list.has_next %}
<a href="?page={{ community_list.next_page_number }}">→</a>
{% endif %}
</div>
{% endif %}
{% endblock %}
Мы вынесли кусок кода в отдельный шаблон и вставляем его через {% include %}
, передавая ему переменную community.
Заметьте конструкцию {% include "community_detail.html" with com=community %}
.
В данном случае with com=community
означает "передать в шаблон пемеренную community и записать её значение в локальную переменную com". Однако если мы заменим com на community в шаблоне community_card.html нам не потребуется указывать with
: Джанго атвоматически передаст значение переменной community потому что она имеет одинаковое имя в обоих шаблонах.
Аналогино создадим шаблон pagination.html
{% if paginated_list.paginator.num_pages > 1 %}
<div class="pagination">
{% if paginated_list.has_previous %}
<a href="?page={{ paginated_list.previous_page_number }}">←</a>
{% endif %}
{% for num in paginated_list.paginator.page_range %}
{% if num == paginated_list.number %}
<span class="current"><b>{{ num }}</b></span>
{% else %}
<a href="?page={{ num }}"> {{ num }}</a>
{% endif %}
{% endfor %}
{% if paginated_list.has_next %}
<a href="?page={{ paginated_list.next_page_number }}">→</a>
{% endif %}
</div>
{% endif %}
И вставим его на место пагинации.
{% extends "base.html" %}
{% block title %}MAI COMMUNITIES{% endblock %}
{% block description %}
Curated list of MAI student communities.
{% endblock %}
{% block content %}
<div class="communities-list">
{% for community in community_list %}
{% include "community_detail.html" with com=community %}
{% endfor %}
</div>
{% include "pagination.html" with paginated_list=community_list %}
{% endblock %}
Так же изменим шаблон community_detail.html:
{% extends "base.html" %}
{% block title %}MAI COMMUNITY {{community.name}}{% endblock %}
{% block description %}
{{community.description}}
{% endblock %}
{% block content %}
{% include "community_card.html" %}
{% endblock %}
Заметье, что теперь мы используем динамические значения блоков title и description: туда подставляется название сообщества и его описание.
Итак мы сократили код примерно вдвое.
-
Создайте страницу "about.html" со статичной текстовой информацией о сайте. Заполните её чем угодно. Для создания страницы необходимо создать новый вид, шаблон и добавить ссылку на вид в website/urls.py. Бонусные очки если вы создадите файл views.py и папку templates в проекте website. Функционал страницы about не относится к студенческим сообществам - он относится к проекту, поэтому будет разумно расположить его в website, а не в приложении communities.
-
Создайте шаблон "navbar.html" который будет содержать список (
<ul>
) из двух ссылок: на страницу about и на страницу home (index). Вставьте этот шаблон в base.html через{% include %}
, чтобы навигационная панель выводилась на любой странице сайта.
Чтобы сделать сайт красивым или хотя бы читабельным нам нужны таблицы стилей, то есть CSS.
Чтобы добавлять CSS, JS и другие статичные файлы добавим директорию для статичных файлов в settings.py нашего проекта, а так же ссылка по которой эти файлы будут доступны.
STATIC_URL = '/static/'
PROJECT_DIR = os.path.dirname(__file__)
STATICFILES_DIRS = (
os.path.join(PROJECT_DIR, 'staticfiles'),
)
Теперь создадим в папке website/website директорию staticfiles, а в ней файл theme.css.
Добавим в этот файл стиль для демонстрации:
h3 {
font-style:bold;
font-size:20pt;
}
Осталось только подключить файл.
Добавим в шаблон "base.html", в контейнер head следующую конструкцию:
{% load static %}
<link href="{% static 'css/theme.css' %}" rel="stylesheet"></link>
Заголовки сообществ стали заметно больше, а мы подключили свой первый стиль.
Однако нам не нужно создавать дизайн сайта прописывая все стили самим. Существует комплект полезных компонентов - Bootstrap - который сделает это за нас.
Установим его как пакет Python. В командной строке введем:
pip install django-bootstrap3
Теперь просто добавим его название в website/website/settings.py INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'communities',
'bootstrap3'
]
И добавим его в контейнер <head>
в base.html
{% load bootstrap3 %}
{% bootstrap_css %}
{% bootstrap_javascript %}
Мы ещё ничего не сделали, а сайт уже выглядит лучше. Теперь мы можем использовать компоненты Bootstrap чтобы навести красоту
Красивые кнопки, кроссбраузерность, автоматическая адаптация под мобильные телефоны и многое другое.
Задание на дом:
-
Сделать коммит изменений с созданием страницы about и шаблона navbar. Оформить pull request в основной репозиторий Лямбда, чтобы изменения были синхронизированы.
-
Оформить navbar с помощью компонентов Bootstrap - http://getbootstrap.com/components/#navbar
-
Оформить community_card.html с помощью панелей Bootstrap - http://getbootstrap.com/components/#panels
-
Оформить pagination.html с помощью пагинации Bootstrap - http://getbootstrap.com/components/#pagination
-
Сделать так, чтобы на странице about кнопка перехода на эту страницу в navbar светилась ярко синим цветом, а на странице home светилась кнопка home. Иначе говоря необходимо:
- Создать стиль
.active
в theme.css - Применять этот стиль к кнопке активной страницы в navbar.html
- Создать стиль
-
Дополнительное задание Сделать возможным загрузку одного изображения для каждого сообщества. Сделать вывод этого изображения в панелях сообществ.
Как всегда, все изменения нужно закомитить в свой репозиторий, а затем оформить pull request в основной репозиторий Лямбда!
Если вам что-то непонятно вы всегда можете спросить в рабочем чате в телеграмм.