Создаем доску объявлений на Django — Публикуем проект на Heroku

Создаем доску объявлений на Django

В данном уроке мы задействуем базу данных, которая понадобится для создания Доски Объявления на Django, при помощи которого пользователи смогут добавлять и читать короткие объявления. Изучим мощный встроенный визуальный интерфейс администратора Django, что позволяет изменять данные, используя удобный набор инструментов. После создания тестов сохраним код на GitHub, а затем запустим приложение на Heroku.

Содержание статьи

Благодаря мощному ORM (Object-Relational Mapping, или объектно-реляционному отображению), в Django есть встроенная поддержка бэкенда многих баз данных: PostgreSQL, MySQL, Oracle и SQLite. Это значит, что разработчики могут написать код в файле models.py, который потом автоматически будет перенаправлен в базу данных. Достаточно обновить секцию DATABASES в файле settings.py.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Во время локальной разработки на Django, по умолчанию использует SQLite, так как данный бэкенд ориентирован на работу с файлами, следовательно, в данном случае является наиболее подходящим. Работа с ним не требует сложной установки. Для сравнения, все остальные базы данных запрашивают отдельные от Django установки и правильную настройку.

Мы начнем использовать SQLite как локальную базу данных, а при переходе на продакшн с Heroku переключимся на PostgreSQL.

Начальная настройка Django приложения

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

  • создаем новую директорию для кода на рабочем столе с названием mb;
  • устанавливаем Django в новом виртуальном окружении;
  • создаем новый проект под названием mb_project;
  • создаем новое django приложение под названием posts;
  • обновляем файл settings.py.

В новой командной строке вводим следующие команды:

Далее мы должны сообщить Django о новом приложении posts. Для этого добавляем его в нижнюю часть секции INSTALLED_APPS файла settings.py.

Затем для создания базы данных выполняем команду migrate в терминале.

Теперь, если при помощи команды ls заглянуть внутрь нашей директории, то можно увидеть, что там появился файл db.sqlite3, который представляет SQLite базу данных.

Технически файл db.sqlite3 впервые создается при выполнении команды migrate или runserver, однако migrate синхронизирует базу данных с текущим состоянием любой модели базы данных в составе проекта и указанной в INSTALLED_APPS. Другими словами, чтобы убедиться в правильности отображения базой данных текущего состояния проекта, вам потребуется запускать migrate (а также makemigrations) при каждом обновлении модели. Вскоре рассмотрим данный вопрос подробнее.

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

Появление знакомой страницы Django при переходе на http://127.0.0.1:8000/ говорит о том, что установлено верно.

django установка

Приветственная страница Django

Создание модели базы данных в Django

Первым делом мы должны создать модель базы данных, где мы можем хранить и отображать записи пользователей. ORM Django автоматически переведет данную модель в таблицу базы данных. В крупных проектах Django используют более сложные и взаимосвязанные между моделями баз данных, однако для нашего простого приложения доски объявлений на Django будет достаточной одной модели.

Откройте файл posts/models.py и обратите внимание на код, который Django предоставляет по умолчанию:

Django импортирует модуль models, который помогает при создании новых моделей баз данных, которые сформируют характеристики данных в нашей базе. Сейчас нам нужно создать модель для хранения текстового содержимого записей доски объявлений, что можно сделать следующим образом:

Обратите внимание, мы создали новую модель базы данных под названием Post, в которой есть текстовое поле базы данных. Мы также уточнили тип содержимого — TextField(). Django предоставляет много различных моделей полей, поддерживающих популярные типы содержимого, например, символы, даты, целые числа, адреса электронной почты и так далее.

Активация моделей в Django

После создания новой модели ее требуется активировать. Заглядывая вперед, вне зависимости от времени создания или модификации существующей модели, нам нужно обновлять Django, что делается в два этапа:

  1. Первым делом при помощи команды makemigrations создается файл миграции. Файлы миграции создают для моделей баз данных отсылки к любым изменениям. Это значит, что, отслеживаются изменения, и в случае необходимости мы можем вовремя исправить возникшие ошибки откатив назад структуры таблиц в базе данных;
  2. Затем мы создаем действующую базу данных при помощи команды migrate, которая выполняет инструкции из файла миграции.

Не забудьте покинуть локальный веб-сервер через комбинацию CTRL+C в командной строке, после чего выполните две следующие команды:

Стоит отметить, что добавлять название модели после makemigrations вовсе не обязательно. Если просто запустить python manage.py makemigrations, тогда файл миграции будет создан для всех доступных изменений в проекте Django. В случае работы с маленьким проектом вроде нашего, где только одно приложение, это не играет особой роли, однако обычно в проектах Django задействовано куда больше приложений! Следовательно, если вы сделаете изменения в модели с несколькими приложениями, итоговый файл миграции будет включать все эти изменения! Вариант не лучший. Файл миграций должен быть настолько мал и ясен, насколько это возможно, так как это значительно облегчает отладку или возврат к предыдущим версиям кода.

По этой причине будет лучше выработать у себя привычку во время выполнения команды makemigrations всегда добавлять название приложения в конец строки.

Как работает Панель Администратора в Django?

Одной из самых сильных сторон Django является его встроенный интерфейс администратора, который предоставляет визуальный набор инструментов для работы с данными. По большей части это стало следствием того, что изначально Django разрабатывался в качестве CMS (системы управления содержимым) для газет. Идея состояла в том, чтобы у журналистов была возможность самостоятельно писать и редактировать статьи в админке без необходимости касаться «кода». Со временем встроенное приложение интерфейса администратора претерпело серьезные изменения, став мощным инструментом для управления всеми аспектами проектов на Django.

Для использования панели администратора Django требуется создать аккаунт супер-пользователя, который будет иметь право войти в админку используя логин и пароль. В командной строке наберите python manage.py createsuperuser, после чего укажите имя пользователя, электронную почту и пароль:

Обратите внимание, что во время ввода пароля он не отображается в консоли командной строки. Это сделано в целях обеспечения безопасности.

Перезагрузите сервер Django при помощи python manage.py runserver, после чего зайдите в браузер и перейдите по адресу http://127.0.0.1:8000/admin/. Откроется страница входа в админку:

message board

Страница входа в админку

Зайдите используя созданные ранее логин и пароль. Откроется домашняя страница панели администратора:

message board

Домашняя страница панели администратора

Где приложение posts? Оно почему-то не показывается на главной странице админки!

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

В текстовом редакторе откройте posts/admin.py и для отображения модели Post добавьте следующий код:

Теперь Django знает, что ему нужно показать приложение posts и его модель базы данных Post в админке. Для отображения данных элементов требуется перезагрузить страницу:

message board

Обновленная главная страница панели администратора

Создадим первую запись доски объявлений. Нажмите кнопку + Add из блока Posts и напишите что-нибудь в текстовом поле.

message board

Новая запись в админке

Далее нажмите кнопку «Save», после чего вы будете перенаправлены на главную страницу Post. Если присмотреться, то появилась проблема: новая запись называется «Post object«, что ничего не говорит о самой записи!

message board

Новая запись в админке

Давайте исправим положение. В файле posts/models.py добавим новую функцию __str__:

Теперь в поле text будут отображаться первые 50 символов. Если перезагрузить в браузере данную страницу, то можно увидеть, что название стало более содержательным и полезным для понимания темы записи.

message board

Новая запись в админке

Намного лучше! Стоит взять себе в привычку добавлять метод __str__ для всех моделей — это повысит читабельность проекта.

Представления (Views), шаблоны (Templates) и URL в Django

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

Начнем с представлений (Views). Ранее мы использовали встроенный генерик Template-View для отображения файла шаблона на домашней странице. Нам нужно составить список содержимого модели рассматриваемой базы данных. К счастью, в веб-разработке задачи подобного рода не редкость — в Django для этого предусмотрен классовый генерик ListView.

В файл posts/views.py введите следующий код:

На первой строке импортируется ListView, а на второй строке импортируется модель Post. В представлении HomePageView мы наследуем ListView, а также уточняем нужную нам модель (Post) и шаблон (home.html).

Первое представление готово, а это значит, что нам все еще требуется настроить URL и создать HTML файл шаблона. Начнем с шаблона. Создаем директорию под названием templates, а внутри нее HTML файл шаблона home.html.

Затем обновляем поле DIRS в файле settings.py, чтобы Django искал шаблоны и в эту директорию.

ListView автоматически возвращает переменную с записями под названием object_list, которую можно включить в цикл через встроенный тег шаблона {% for %}. В цикле мы создадим переменную под названием post, после чего получаем доступ к полю, которое нужно отобразить post.text.

Название переменной object_list многим может показаться не очень подходящим. При помощи атрибута context_object_name её можно переименовать. Здесь Django вновь показывает гибкость возможностей настройки.

Вернемся к файлу posts/views.py и добавим следующее:

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

Также, не забудьте обновить шаблон, чтобы он отсылался на all_posts_list, а не на object_list.

На последнем этапе требуется настроить URLConfs. Начнем с файла mb_project/urls.py, где нужно просто включить posts добавив его через include() на второй строке.

Далее создаем файл настройки URL маршрутов приложений url.py:

Обновляем его:

Перезагружаем веб-сервер через python manage.py runserver и переходим на домашнюю страницу http://127.0.0.1:8000/, где появился список записей доски объявлений.

message board

Домашняя страница с записями

Мы практически подошли к финалу. Давайте создадим еще несколько записей на доске объявлений через админку Django, чтобы убедиться в правильности их отображения на домашней странице.

Добавление новых записей в приложении Django

Для добавления новых записей на доску объявлений вернемся в панель администратора и создадим еще две записи. У нас все выглядит следующим образом:

message board

Создание новой записи через админку

message board

Создаем третью запись через админку

message board

Обновленная секция записей в админке

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

message board

Домашняя страница с тремя записями

Все работает, поэтому пришло время для загрузки нашего кода в репозиторий на github.

Командная строка

Пишем TestCase тесты для доски объявления на Django

Ранее мы уже тестировали статичные страницы, для чего использовали SimpleTestCase. Однако теперь домашняя страница работает с базой данных, поэтому требуется задействовать TestCase, что позволит создать тестовую базу данных для проверки. Иными словами, пропадает необходимость запускать тесты на действующей базе данных. Вместо этого создается отдельная тестовая база данных, наполняется образцами данных, после чего выполняется проверка. Данный подход является наиболее безопасным и производительным.

Начнем с добавления пробной записи, а затем проверим, правильно ли оно сохранилась в базе данных. Важно, чтобы все тестовые методы начинались с префикса test_. Таким образом Django будет знать, что проверять. Код выглядит следующим образом:

В верхней части мы импортировали модуль TestCase, который дает возможность создать образец базы данных и таблицу модели Post. Мы создали новый класс PostModelTest и добавили метод setUp для создания новой базы данных, у которой только одна запись — это пост с текстовым полем, содержащим строку «just a test».

Теперь можно запустить первый тест test_text_content для проверки того, что поле в базе данных действительно содержит фразу just a test. Мы создали переменную post, которая содержит запись с ID = 1 в нашей модели Post.

Обратите внимание, что Django автоматически настраивает id. Если мы добавим новую запись, то ее id будет 2, у следующей за ней id станет 3 и так далее.

Следующая строка использует f-строки, ставшие отличным введением в Python 3.6, что позволило добавлять переменные напрямую в строки — главное, чтобы данные переменные находились в фигурных скобках {}. Здесь мы указываем, что в expected_object_name будет значение от post.text, т.е. фраза just a test.

На последней строке кода мы используем assertEqual, что проверяет, действительно ли заново созданная запись совпадает с тем, что мы добавили сверху. Запустите тест через командную строку при помощи команды python manage.py test.

Тест пройден!

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

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

  • она действительно существует и возвращает HTTP код состояния 200?
  • она использует HomePageView как представление?
  • она использует файл home.html в качестве шаблона?

Можно включить все вышеупомянутые тесты в новый класс под названием HomePageViewTest. Обратите внимание, что для получения прямого доступа к названию представления мы импортируем reverse и обращаемся к названному URL home. Зачем использовать такой способ? URL структура меняется на протяжении разработки проекта, однако именованные URL, как правило, этого не делают.

Нам нужно добавить импорт reverse и создать новый класс HomePageViewTest для теста.

Если вы запустите тесты, то увидите, что все работает.

Почему в выводе упоминается четыре теста, а не шесть? Дело в том, что методы setUp по сути не являются тестами — они считаются вспомогательными функциями. Только функции, которые начинаются с test* и находятся внутри файла tests.py будут запущены как тесты после выполнения команды python manage.py test.

На этом с редактированием кода для тестов закончим и закоммитим изменения на git.

Сохраняем код проекта на Github

Нам нужно сохранить код на GitHub. У вас уже должен быть GitHub аккаунт, осталось только создать новое хранилище — назовем его mb-app. Не забудьте нажать кнопку «Private».

На следующей странице пролистайте до строчки «…or push an existing repository from the command line». Скопируйте и вставьте две указанные команды в терминал. Результат должен быть как в примере ниже, только вместо моего имени пользователя на GitHub (wsincent) будет указано ваше.

Примеры настроек Heroku для Django проекта

У вас уже должен быть настроенный аккаунт от Heroku. Теперь для размещения нашей доски объявлений в интернете, нам нужно сделать определенные изменения в файлах проекта:

  • обновить файл Pipfile.lock;
  • добавить новый Procfile;
  • установить Gunicorn;
  • обновить settings.py.

В Pipfile уточните Python версию — в нашем случае это 3.7. В нижнюю часть файла добавьте следующие две строчки.

Pipfile

Для генерации подходящего Pipfile.lock запустите pipenv lock.

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

Мы говорим Heroku, что нужно использовать Gunicorn в качестве веб-сервера и изучить файл mb_project.wsgi для дальнейших инструкций.

Procfile

Далее устанавливаем Gunicorn, что будет задействован в качестве WSGI HTTP сервера. Внутренний веб-сервер в Django по-прежнему используем при локальной разработке.

Обновляем ALLOWED_HOSTS в файле settings.py.

Вот и все. Добавляем и коммитим новые изменения через git, после чего размещаем код на GitHub.

Запускаем доску объявлений на Django в Heroku

Убедитесь, что вы зашли на верный аккаунт Heroku.

Запустите команду create, тогда Heroku случайным образом сгенерирует название приложения.

Теперь скажем Heroku игнорировать статические файлы.

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

Можете открыть URL нового проекта из командной строки, набрав heroku open, что запустит новое окно браузера. Вот что получилось у нас:

message board

Рабочий сайт

SQLite vs PostgreSQL

Сейчас наше приложение работает с SQLite — как локально, так и на Heroku. Тем не менее, возникает проблема: легкость SQLite обусловлена зависимостью от файловой системы, которая на Heroku обновляется каждые 24 часа! Это значит, что данные, добавленные в запущенную базу данных, довольно скоро будут удалены.

Для запущенного рабочего приложения решением проблемы станет переключение на готовый к работе бэкенд, такой как PostgreSQL, что будет также использован и локально. В продакшене на Heroku его можно использовать напрямую через Postgres add-on, у которого даже есть бесплатный план «Hobby Dev». Неудобство заключается в том, что для локального использования PostgreSQL требуется дополнительная настройка конфигурации, которая будет сложна для новичка.

Заключение

Мы создали, протестировали и разместили наше первое приложение с базой данных. На простом примере было показано, как создать модель базы данных, обновить ее при помощи панели администратора, а затем отобразить содержимое на веб-странице. Однако, чего-то не хватает, не так ли?

На практике, пользователи используют разнообразные формы для взаимодействия с сайтом. Не у каждого ведь есть доступ к панели администратора. В следующем уроке мы займемся созданием блога на Django, что будет использовать формы, при помощи которых пользователи смогут создавать, редактировать и удалять записи. Для оптимизации интерфейса мы также добавим CSS стили.