# Подготовка третьего проекта --- ## Документация ---- Наша электронная доска объявлений позволит зарегистрированным пользователям публиковать объявления о продаже чего-либо. Объявления будут разноситься по рубрикам, причем структура рубрик будет иметь два уровня иерархии. ---- Для вывода списка объявлений мы применим пагинацию, т. к. объявлений может оказаться очень много, и страница, содержащая все объявления, будет слишком большой. Также мы предусмотрим возможность поиска объявлений по введенному посетителем слову. ---- Под любым объявлением (на странице сведений об объявлении) может быть оставлено произвольное количество комментариев. Оставлять комментарии будет позволено любому пользователю, в том числе и гостю. ---- В составе объявления пользователь может поместить основную графическую иллюстрацию, которая будет выводиться и в списке объявлений, и в составе сведений об объявлении, а также произвольное количество дополнительных иллюстраций,которые можно будет увидеть лишь на странице сведений об объявлении. ---- Процедура регистрации нового пользователя на сайте будет разбита на два этапа. На первом этапе посетитель вводит свои данные на странице регистрации, после чего на указанный им адрес электронной почты приходит письмо с гиперссылкой, ведущей на страницу активации. На втором этапе посетитель переходит по гиперссылке, полученной в письме, попадает на страницу активации и становится полноправным пользователем. ---- Сайт доски объявлений включит в себя следующие страницы: * главная * страница списка объявлений * страница сведений о выбранном объявлении * страницы регистрации и активации нового пользователя; * страницы входа и выхода; ---- Продолжение: * страница профиля зарегистрированного пользователя * страницы добавления, правки, удаления объявлений; * страницы изменения пароля, правки и удаления пользовательского профиля; * страницы сведений о сайте, о правах его разработчика, пользовательского соглашенияи пр. --- Подготовка проекта ---- Запустим командную строку, перейдем в папку, в которой будет находиться папка нового проекта, и подадим команду на создание проекта bboard; `django-admin startproject bboard .` ---- изменим имя файла, в котором будет храниться база данных сайта — на bboard.data и код языка для вывода системных сообщений и страниц административного сайта — на "ru" ``` DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'bboard.data'), } } LANGUAGE_CODE = 'ru' ``` ---- Добавим путь для поиска шаблонов ``` TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { ... }, }, ] ``` ---- ДОбавим путь для поиска static файлов: ``` STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] ``` ---- В командной строке перейдем в папку проекта и подадим команду на создание приложения `main`: `python manage.py startapp main` ---- Добавим в объявление конфигурационного класса MainConfig атрибут verbose_name с названием приложения: ``` class MainConfig(AppConfig): name = 'main' verbose_name = 'Доска объявлений' ``` ---- Вернемся к модулю настроек проекта `settings.py` и добавим только что созданное приложение в список зарегистрированных в проекте: ``` INSTALLED_APPS = [ 'main.apps.MainConfig', ] ``` ---- Для оформления страниц используем популярный CSS-фреймворк Bootstrap 4. `pipenv install django-bootstrap4` ---- Добавим в список зарегистрированных в проекте приложение bootstrap4 — программное ядро библиотеки django-bootstrap4: ``` INSTALLED_APPS = [ 'bootstrap4', ] ``` --- ## Оформление сайта ---- Далее приведен код базового шаблона. Сохраним его в файле templates\layout\basic.html. ``` <!DOCTYPE html> {% load bootstrap4 %} {% load static %} <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>{% block title %}Главная{% endblock %} - Доска объявлений</title> {% bootstrap_css %} <link rel="stylesheet" type="text/css" href="{% static 'main/style.css' %}"> {% bootstrap_javascript jquery='slim' %} </head> <body class="container-fluid"> <header class="mb-4"> <h1 class="display-1 text-center">Объявления</h1> </header> <div class="row"> <ul class="col nav justify-content-end border"> <li class="nav-item"><a class="nav-link" href="#">Регистрация</a></li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Профиль</a> <div class="dropdown-menu dropdown-menu-right"> <a class="dropdown-item" href="#">Moи объявления</a> <a class="dropdown-item" href="#">Изменить личные данные</a> <a class="dropdown-item" href="#">Изменить пароль</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#">Выйти</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#">Удалить</a> </div> </li> <li class="nav-item"><a class="nav-link" href="#">Bxoд</a></li> </ul> </div> <div class="row"> <nav class="col-md-auto nav flex-column border"> <a class="nav-link root" href="{% url 'main:index' %}">Главная</a> <span class="nav-link root font-weight-bold"> Heдвижимость </span> <a class="nav-link" href="#">Жилье</a> <a class="nav-link" href="#">Склады</a> <a class="nav-link" href="#">Гаражи</a> <span class="nav-link root font-weight-bold" href="#"> Транспорт</span> <a class="nav-link" href="#">Легковой</a> <a class="nav-link" href="#">Грузовик</a> </nav> <section class="col border py-2"> {% bootstrap_messages %} {% block content %} {% endblock %} </section> </div> <footer class="mt-3"> <p class="text-right font-italic">&copy; любой ТМ на ваш вкус</p> </footer> </body> </html> ``` ---- ``` <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> ``` Этот метатег, помещенный в секцию заголовка страницы (в парный тег `<head>`), необходим для того, чтобы Bootstrap правильно обработал страницу; ---- ``` <title>{% block title %}Главная{% endblock %} - Доска объявлений</titlе> ``` В теге `<title>` мы создаем первый блок, назвав его title. С его помощью будет выводиться название страницы; ---- ``` {% bootstrap_css %} ``` Привязываем к странице таблицы стилей Bootstrap; ---- ``` <link rel="stylesheet" type="text/css" href="{% static 'main/style.css’ %}"> ``` Привязываем таблицу стилей static\main\sty1e.css, которую создадим чуть позже. В ней мы запишем некоторые специфические для нашего сайта стили; ---- ``` {% bootstrap_javascript jquery='slim' %} ``` Привязываем файлы веб-сценариев с программным кодом Bootstrap вместе с сокращенной редакцией библиотеки jQuery, без которой не заработает созданное нами раскрывающееся меню; ---- ``` <body class="container-fluid"> </body> ``` К телу страницы (тегу `<body>`) привязываем стилевой класс container-fluid, как того требует Bootstrap; ---- ``` <header class="mb-4"> <h1 class="display-l text-center">Oбъявлeния</h1> </header> ``` Стилевой класс mb-4, привязанный к элементу страницы, установит у него достаточно большой отступ снизу. А стилевые классы display-1 И text-center, привязанные к заголовку, предпишут веб-обозревателю вывести текст величенным шрифтом и выровнять его посередине; ---- ``` <div class="row"><ul class="col . . ."></ul></div> ``` Bootstrap позволяет выполнять табличную верстку без участия собственно таблиц. Стилевой класс row, привязанный к элементу страницы, вынуждает его вести себя как строка таблицы, а стилевой класс col — как ячейка в этой строке. ---- ``` <ul class=". . . nav justify-content-end border"> <li class="nav-item"> <a class="nav-link"href="#">Peгистрация</a> </li> </ul> ``` Упомянутый ранее маркированный список мы используем для создания горизонтальной полосы навигации. Для этого привяжем к нему стилевой класс nav. Стилевой класс justify-content-end укажет выровнять пункты полосы навигации по правому краю, а стилевой класс border создаст рамку вокруг нее. ---- ``` <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Профиль</a> <div class="dropdown-menu dropdown-menu-right"> <a class="dropdown-item" href="#">Moи объявления</a> <a class="dropdown-item" href="#">Изменить личные данные</a> <a class="dropdown-item" href="#">Изменить пароль</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#">Выйти</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#">Удалить</a> </div> </li> ``` А данный код создает в полосе навигации пункт с раскрывающимся меню. Для этого внутрь тега `<li>` помещается, помимо гиперссылки, еще и блок, который создаст само меню. ---- ``` <div class="row"> <nav class="col-md-auto nav flex-column border"> ... </nav> <section class="col border py-2"> ... </section> </div> ``` Здесь мы снова применили табличную верстку, но на этот раз из двух ’’ячеек”: семантической панели навигации (тега `<nav>`) и семантической секции страницы (тега `<section>`). ---- ``` <nav class="col-md-auto nav flex-column border"> <a class="nav-link root" href="{% url 'main:index' %}">Главная</a> <span class="nav-link root font-weight-bold"> Heдвижимость </span> <a class="nav-link" href="#">Жилье</a> <a class="nav-link" href="#">Склады</a> <a class="nav-link" href="#">Гаражи</a> <span class="nav-link root font-weight-bold" href="#"> Транспорт</span> <a class="nav-link" href="#">Легковой</a> <a class="nav-link" href="#">Грузовик</a> <a class="nav-link root" href="{% url 'main:other' page='about' %}">О сайте</a> </nav> ``` Мы привязали к семантической панели навигации стилевые классы nav и fiexcoiumn (чтобы превратить ее в вертикальную панель навигации в стиле Bootstrap), а также создающий рамку стилевой класс border. ---- Разные пункты панели навигации мы формируем тремя разными способами: * пункты, ведущие на служебные страницы * пункты, обозначающие рубрики верхнего уровня (надрубрики) * пункты, ведущие на рубрики нижнего уровня (подрубрики) ---- ``` <section class="col border py-2"> {% bootstrap_messages %} {% block content %} {% endblock %} </section> ``` К семантической секции мы также привязали стилевые классы border и ру-2. Первый нам уже знаком, а второй установит для тега небольшие внутренние отступы сверху и внизу, чтобы содержимое тега не примыкало к рамке вплотную. В семантическую секцию мы поместили код, выводящий всплывающие сообщения, и блок content, в котором будет выводиться основное содержимое страниц; ---- ``` <footer class="mt-3"> <p class="text-right font-italic">&copy; любой ТМ на ваш вкус</p> </footer> ``` "Поддон" сайта мы создаем специализированным тегом `<footer>`. Стилевой класс mt-з укажет для него внешний отступ сверху средних размеров, чтобы отделить его от вышерасположенных элементов. Чтобы выровнять текст абзаца по правому краю и вывести его курсивом, мы привязали к тегу <р> стилевые классы text-right И font-italic. ---- Далее приведен код таблицы стилей static\main\style.css. Создадим ее. ``` header h1 { background: url("bg.jpg") left / auto 100% no-repeat, url("bg.jpg") right / auto 100% no-repeat; } .root { font-size: larger; } ``` ---- Главную страницу сделаем совсем минималистичной— только чтобы удостовериться, работает ли сайт. ``` from django.shortcuts import render def index(request): return render(request, 'main/index.html') ``` ---- Создадим шаблон главной страницы templates\main\index.html, записав в него сдедующий код ``` {% extends "layout/basic.html" %} {% block content %} <h2>Последние 10 объявлений</h2> {% endblock %} ``` ---- Займемся списком маршрутов уровня проекта, хранящегося в модуле urls.py пакета конфигурации. ``` from django.contrib import admin from django.urls import path, include from django.conf import settings from django.contrib.staticfiles.views import serve from django.views.decorators.cache import never_cache urlpatterns = [ path('admin/'', admin.site.urls), path('', include('main.urls')), ] if settings.DEBUG: urlpatterns.append(path('static/<path:path>', never_cache(serve))) ``` ---- `serve` - Представление, которое раздает статические файлы при разработке. Это представление автоматически используется командой runserver (при DEBUG равном True). `never_cache` - Декоратор добавляет заголовок к ответу, указывая, что странице не должна никогда кэшироваться. ---- ``` from .views import other_page uripatterns = [ path('<str:page>/', other_page, name='other'), path('', index, name='index'), ] ``` ---- В модуль views.py пакета приложения, где хранится код контроллеров, добавим код контроллера-функции other_page(), приведенный в листинге 31.7. ``` from django.http.import HttpResponse, Http404 from django.template.import TemplateDoesNotExist from django.template.loader import get_template def other_page(request, page): try: template = get_template('main/' + page + '.html') except TemplateDoesNotExist: raise Http404 return HttpResponse(template.render(request=request)) ``` ---- Странице со сведениями о сайте и правах его разработчиков дадим имя about. Код формирующего ее шаблона templates\main\about.html приведен в листинге 31.8. ``` {% extends "layout/basic.html" %} {% block title %}O сайте{% endblock %} {% block content %} <h2>О сайте</h2> <p>Сайт для публикации объявлений о продаже, разбитых на рубрики.</р> {% endblock %} ``` ---- Откроем базовый шаблон templates\layout\basic.html и добавим в левую панель навигации такой код: ``` <nav class="col-md-auto nav flex-column border"> <a class="nav-link root" href="{% url 'main:other' page='about' %}">О сайте</a> </nav> ``` ---- `<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>`
{"metaMigratedAt":"2023-06-16T14:28:14.075Z","metaMigratedFrom":"Content","title":"Подготовка третьего проекта","breaks":true,"contributors":"[{\"id\":\"0d39d5a3-691d-488c-8f1e-1a0fb0be4f13\",\"add\":16247,\"del\":1454}]"}
    178 views