Django. Деплой. Бесплатные хостинги

Введение

Деплой - перенос сайта на сервер. Процесс, который в первый раз может показаться трудным и запутанным, но с практикой, конечно, вас уже не пугают слова nginx, gunicorn и прочие вещи связанные с развертыванием приложения в интернете. Развертывание, сборка и вытекающие из этого вещи выросли в отдельную профессию, которая называется DevOps-инженер. Правда, DevOps это больше разговор про автоматизацию, с использованием Docker, GitLub и еще большим количеством различных инструментов.
На момент написания этого материала у нас написано три сайта в первом блоке и один во втором, эти сайты и будут материалом для обучения. Первые сайты развернем на бесплатных серверах heroku и pythonanywhere.

Heroku. Деплой первого сайта

Помните самый первый сайт, который мы писали? Это был сайт, на котором можно сгенерировать случайную последовательность символов. Его мы развернем на бесплатном сервере Heroku. Heroku поддерживает python и ряд других языков, хотя изначально создавался только под Ruby. В регистрации на Heroku нет ничего необычного, вы можете авторизоваться просто через ваш GitHub. Но перед загрузкой сайта на сервер с ним необходимо произвести некоторые манипуляции. Этим мы с вами сначала и займемся.

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

У меня уже нет проекта на компьютере, чтоб его загрузить в папку с проектом воспользуемся командой
git clone (ссылка проекта для загрузки с github)
для получения этой ссылки откройте репозиторий проекта на github, нажмите на зеленую кнопку code и возьмите HTTPS ссылку. Таким образом папка с проектом снова у нас на компьютере.

requirements.txt. favicon.ico

Первым делом быстренько поговорим про favicon.ico. Мы не добавляли ее не в один ранее созданный проект, на примере первого посмотрим как это делается. favicon.ico это иконка для вкладки сайта и скорее всего, если вы во время работы над вашими проектами обращались к консоли в браузере, то видели ошибку примерно такого характера

GET http://127.0.0.1:8000/favicon.ico [HTTP/1.1 404 Not Found 0ms]

она как раз и говорит, что на нашем сайте не хватает иконки. Иконка это уменьшенное лого вашего сайта и для создания такой иконки существуют различные сервисы. Один из них favicon.io. На нем можно создать себе лого формата .ico. В форме на странице генерации вы можете написать какую-то последовательность букв, выбрать цвет, шрифт, размер шрифта, жирность шрифта и формат иконки: круглый, квадратный или с закругленными краями, после этого сгенерированную иконку можно загрузить и использовать для своего сайта. Либо вы можете на этом же сайте во вкладке converter вашу картинку преобразовать в формат .ico и получить графическую иконку.
Я создам иконку в генераторе и скачаю ее. Скачивается zip архив, распаковываем его, среди всех файлов выбираем файл favicon.iсo и добавляем в папку static нашего проекта, папка static должна лежать в корне проекта.
В первом нашем проекте мы не писали настройки для статики, добавим их

STATIC_URL = '/static/'

#STATIC_ROOT = os.path.join(BASE_DIR, 'static') 

STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [STATIC_DIR]


И осталось только подключить иконку в base.html, в нашем первом проекте главный html называется index.html.

index.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
...
    <title>genlogin</title>
    <link rel="icon" href="{% static 'favicon.ico' %}">
    ...

Добавляется иконка в шапке в теге link. Помимо добавления иконки приведем index.html к нормальному виду, добавив классическую разметку html 5 документа. style.css я тоже сразу перенес в корневую папку static.

С иконкой разобрались.

Следующий шаг это добавление к проекту файла requirements.txt.

requirements.txt мы уже добавляли в одном из проектов, делается это командой

pip freeze > requirements.txt

После применения этой команде в папке, находясь в которой вы эту команду применили, появится файл requirements.txt со всеми библиотеками и их версиями установленными в ваше виртуальное окружение, иногда этот файл может называться req.txt. Я писал все сайты, которые мы разбирали с вами, в одном виртуальном окружении, поэтому requirements.txt содержит у меня все зависимости всех проектов, конечно, такой подход не правильный. На практике, любой проект, который вы планируете как то распространить или просто залить на github для дальнейшего самостоятельного использования следует создавать в индивидуальном виртуальном окружении. Устанавливать лишние зависимости нам ни к чему, я почищу файлик requirements.txt вручную и уберу от туда все лишнее. Первый проекты у нас использовали чистый django, поэтому это всего 4 библиотеки.
Если у вас вдруг тоже несколько проектов в одном окружении и requirements.txt содержит явно больше библиотек, чем используется в вашем проекте вы можете создать рядом новое окружение, поставить в него пустой django и запускать ваш проект, ошибки будут подсказывать каких библиотек вам не хватает. После установки всех нужных библиотек pip freeze перезапишет ваш requirements.txt и вы сможете отправить на github проект без лишних зависимостей. Но для того чтобы подобным не заниматься лучше на старте проекта позаботиться о чистом виртуальном окружении.

Разделение настроек. .gitignore

Есть необходимость в разделение настроек на локальные и на настройки для продакшена. Есть несколько подходов, но все они сводятся у тому, чтобы на вашем локальном устройстве запускался один файл с настройками, а на боевом сервере другой. Например, можно сделать это добавлением в каталог, где хранится файл settings.py, пакета с именем settings. Напоминанию для того чтобы папка считалась пакетом необходимо добавить в нее файл __init__.py. Теперь, когда django будет пробегаться по проекту в поисках файла settings.py он будет натыкаться на пакет settings и искать настройки там. В этот пакет перенесем файл settings.py и переименуем его, например, в local_settings.py и рядом с этим файлом создадим еще один файл и назовем его, например, prod_settings.py. Теперь добавим немного кода в __init__.py.

firstsite/settings/__init__.py
from .prod_settings import *

try:
    from .local_settings import *
except ImportError:
    pass

Первым делом заходя в пакет setting будет исполняться файл __init__.py, внутри которого мы импортируем настройки для продакшена и после попробуем импортировать локальные настройки, если таковые будут мы перезапишем настройки на локальные и будем использовать их, в случае отсутствия локальных настроек так будем использовать настройки для продакшена. Поскольку файл local_settings.py на github заливаться не будет, то на продакшене будут использоваться нужные настройки.

Теперь касаемо самих файлов с настройками. В продакшн настройках нам следует изменить DEBUG режим в значение False, заполнить список ALLOWED_HOSTS, пока у нас нет ip для проекта можно добавить туда локальный ip 127.0.0.1 или просто *, ALLOWED_HOSTS хранит либо ip, либо домены проектов. Также в реальных проектах используются более мощные СУБД, чем sqlite3, зачастую postgresql и Heroku имеет бесплатный плагин для поддержки postgres, так что настройки для БД тоже стоит изменить. В нашем первом сайте мы вообще не создавали никаких моделей, но любой Django проект по умолчанию уже содержит базы данных, например, модель пользователя, поэтому и в случае первого проекта изменим СУБД на postgresql.

Также немаловажный момент, секретный ключ вашего сайта не должен видеть никто, поэтому в продакшн файле его стоит изменить.

Помимо этого стоит разделить настройки статики для локальной и продакшн версий.

local_settings.py
...
STATIC_URL = '/static/'

STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [STATIC_DIR]
...
prod_settings.py
...
DB_NAME = os.environ.get('DB_NAME')
DB_PASSWORD = os.environ.get('DB_PASSWORD')
DB_HOST = os.environ.get('DB_HOST')
DB_USER = os.environ.get('DB_USER')
# SECRET_KEY = os.environ.get('SECRET_KEY')

SECRET_KEY = 'django-insecure-sp9-@gd3!s*5rcuf*$g2224yan4bu@9qawdwa31=p$ai8g#3^1=g5-*_)=)'

DEBUG = False

ALLOWED_HOSTS = ['127.0.0.1']
...

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': DB_NAME,
        'USER': DB_USER,
        'PASSWORD': DB_PASSWORD,
        'HOST': DB_HOST,
        'PORT': '5432',
    }
}
...

STATIC_URL = '/static/'

STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [STATIC_DIR]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
...

На данный момент добавим такие изменения. DEBUG = False и ALLOWED_HOSTS выше обсуждалось.
Посмотрим на DATABASES
Преднастройки для СУБД postgresql всегда содержат следующие параметры, но вместо явного указания значений мы воспользуемся переменными, которые определим вначале файла prod_settings.py. Оставим только PORT, по умолчанию он всегда 5432. Значения для этих переменных мы получим, когда создадим проект на Heroku и подключим к нему плагин Heroku Postgres, посмотрим как это делается позже. Такую же переменную создадим для секретного ключа, но пока у нас нет проекта на Heroku можем загрузить файл с настройками с явно указанным ключом. Название 'staticfiles' в переменной STATIC_ROOT это условие необходимое именно для загрузки проектов на Heroku.

К файлу с настройками мы еще вернемся.

Теперь что касается .gitignore, готовый .gitignore под ваш язык, ОС и прочие условия можно найти в интернете, я сделал также, проверьте, чтоб в вашем файле был local_settings.py. db.sqlite3, media, venv, env и прочие вещи в таких файлах обычно всегда учтены, но проверить тоже стоит.

Пример .gitignore

Оставшиеся настройки для Heroku

Теперь посмотрим на настройки, которые касаются в большей степени Heroku. Первым делом установим необходимые зависимости.

pip install gunicorn whitenoise dj-database-url psycopg2-binary

gunicorn - веб сервер, whitenoise - библиотека для работы со статикой, psycopg2-binary - плагин для postgresql и dj-database-url - плагин для соединения БД с Heroku. После установки этих зависимостей необходимо обновить requirements.txt.
Для работы gunicorn с Heroku необходимо добавить в корень проекта файл Procfile, внутри которого нужно прописать следующую настройку
web: gunicorn firstsite.wsgi
где firstsite имя папки где лежит файл wsgi.py.
Теперь давайте наконец создадим проект на Heroku и добавим оставшиеся настройки в prod_settings.py.
Перейдите на Heroku и создайте новый аккаунт. На момент июня 2022 года, если вы находитесь на территории РФ, и у вас ранее не было аккаунта на Heroku, новый аккаунт будет необходимо регистрировать с VPN. Можете использовать, например, Proton VPN. После регистрации аккаунта заходить в него можно без VPN. После создания аккаунта вам предложат создать новый проект, дайте ему название и выберете сервер США или Европа.

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

Теперь нужно добавить в проект переменные используемые в prod_settings.py. Сначала во вкладке Resources найдите плагин Heroku Postgres и установите его.

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

Во вкладе settings у нас есть все необходимые данные, осталось только прописать их в проекте с теми именами, которые мы используем в prod_settings.py.

Для этого перейдем в settings проекта и в Config Vars добавим необходимые переменные. DATABASE_URL добавляется автоматически, когда мы устанавливаем Heroku Postgres, DB_HOST, DB_NAME, DB_PASSWORD и DB_USER мы берем из settings Heroku Postgres.
Тут же добавим SECRET_KEY, я написал там тот же ключ, что и в prod_settings.py, на деле, конечно, вам нужно написать там другой ключ, который ранее нигде не светился. Необходимые переменные добавлены. Вернемся в prod_settings.py и произведем оставшиеся изменения.

prod_settings.py
...
DB_NAME = os.environ.get('DB_NAME')
DB_PASSWORD = os.environ.get('DB_PASSWORD')
DB_HOST = os.environ.get('DB_HOST')
DB_USER = os.environ.get('DB_USER')
SECRET_KEY = os.environ.get('SECRET_KEY')
...
SECRET_KEY = SECRET_KEY

DEBUG = False

ALLOWED_HOSTS = ['genlogin.herokuapp.com']
...

MIDDLEWARE = [
    ...
    'whitenoise.middleware.WhiteNoiseMiddleware',
    ...
]

Раскомментируем SECRET_KEY и вместо явного указания ключа напишем SECRET_KEY = SECRET_KEY, Heroku сам найдет нужное значение в проекте и подставит его в настройки, так же как и с настройками для БД. В ALLOWED_HOSTS мы теперь можем поместить домен нашего проекта. Также необходимо добавить в MIDDLEWARE 'whitenoise.middleware. WhiteNoiseMiddleware', я расположил ее второй по счету, это настройка необходимая для корректной работы библиотеки whitenoise.

Предварительные настройки закончены. Теперь сделайте пуш на github со всеми внесенными изменениями в settings.py, с файлом Procfile и с обновленным requirements.txt, где должны быть добавленные для Heroku библиотеки.

Запуск Heroku проекта

С настройками закончено, актуальная версия проекта лежит в репозитории подключенному к Heroku, осталось только пересобрать проект и можно пользоваться. Вернемся во вкладу Deploy и спустимся вниз до Manual deploy.

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

Если процесс завершается ошибкой перепроверьте наличие Procfile в проекте и библиотеки в requirements.txt.
Все, проект загружен и доступен для использования по домену вашего Heroku проекта.
Осталось произвести миграции.

Для этого находясь в проекте нажмите More и выберите Run console, console уже работает в venv режиме, так что вы можете прописывать необходимые вам команды. Например, тут же вы можете создать суперпользователя и сразу зайти в admin панель не перезапуская проект.
Если же вы внесли какие-то изменения во views, в шаблоны, в models и прочие места проекта, то вам нужно будет сделать новый пуш на github и пересобрать проект кнопкой Deploy Branch, следующие разы будут быстрее, потому что необходимые зависимости уже будут установлены.

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

genlogin на github, можете использовать его для тренировки деплоя через Heroku.

PythonAnywhere. Деплой второго сайта

Для публикации второго сайта воспользуемся еще одним бесплатным сервисом PythonAnywhere, из названия становится понятно, что PythonAnywhere специализируется только на Python. Предлагаю вам сразу зарегистрироваться на сайте, в отличие от Heroku, VPN тут не требуется. После этого можно клонировать проект с github, можете взять также наш второй учебный сайт, можете взять самый первый коммит dietforurcle v1.1, он еще не содержит никаких изменений для публикации. И первым делом, опять же, приступим к подготовке проекта к публикации.

Подготовка к публикации

Для создания favicon воспользуемся уже знакомым сервисом favicon.io

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

Добавим файл .gitignore, я воспользуюсь тем же файлом, что использовался в первом проекте.

Пример .gitignore

Базу данных Postgres мы можем использовать только с платного тарифа. На бесплатном тарифе есть возможность использовать MySQL. Файлом setting.py мы займемся позже.

На этом подготовка к публикации на стороне проекта закончена, осталось сделать свежий push на github и можно переходить к настройкам на стороне PythonAnywhere. ссылка на commit готовый к публикации.

Настройки pythonanywhere

К этому моменту я думаю, что вы уже зарегистрированы на PythonAnywhere. После регистрации вы оказываетесь в личном кабинете во вкладке Dashboard.

Перейдем во вкладу Console для добавления консоли, будем пользоваться Bash. На триальной версии можно иметь только 2 одновременно работающие консоли, но нам хватит и одной. После нажатия на bash мы попадем в консоль. По умолчанию мы оказываемся в домашней директории вида home/(логин).

Bash
17:13 ~ $ ls
README.txt
17:13 ~ $ git clone https://github.com/IlyaTsarkov/dietforurcle.git

Командой ls можно просматривать содержимое папки, в которой мы сейчас находимся. README.txt - файл, который создается автоматически в домашней директории при регистрации, вы можете его удалить.
В домашнюю директории нам нужно склонировать наш готовый к публикации проект.

Bash
17:14 ~ $ python3 -m venv venv
17:15 ~ $ ls
README.txt dietforurcle venv
17:15 ~ $ source venv/bin/activate
(venv) 17:15 ~/dietforurcle (master)$ pip install -r requirements.txt 

После этого создадим виртуальное окружение в домашней директории, активируем его и внутри него установим необходимые зависимости их requirements.txt.

После успешного клонирования и установки всех зависимостей перейдем во вкладку web кабинета pythonanywhere. Нажмем Add a new web app и перед нами появится окно создания приложения, на первом этапе мы увидим доменное имя нашего будущего приложения.

Далее нам предложат выбрать преднастроенные конфигурационные шаблоны для разных python фреймворков, нас интересует ручная настройка, поэтому выберем последний пункт. На следующем этапе вам предложат выбрать python версию, если у вас нет твердых требований к версии python - выбирайте саму последнюю. И на последнем этапе нам скажут, что мы должны настроить wsgi файл для развертывания нашего приложения.

После последнего подтверждения перед нами откроется кабинет приложения с еще незаполненными настройками.
Займемся их заполнением.

В Source code нам необходимо указать путь до папки, в которой находится файл manage.py
Working directory заполняется автоматически, но вы можете перепроверить, чтобы это был путь до вашей домашней директории
WSGI configuration file мы подробнее разберем совсем скоро
В Virtualenv нужно указать путь до виртуального окружения.

Обратите внимание также на Log files, а конкретно на Error log, если вдруг у вас будет что-то не получаться при запуске сервера, то в этом файле вы можете посмотреть историю ошибок, зачастую это бывает очень полезно.

Ниже добавляются пути для /media/ и /static/. Предварительно эти папки нам нужно создать. Для этого вернемся в Bash.

Bash
(venv) 17:21 ~/dietforurcle (master)$ mkdir media static
(venv) 17:21 ~/dietforurcle (master)$ cd media
(venv) 17:21 ~/dietforurcle/media (master)$ pwd
/home/kavomain/dietforurcle/media
(venv) 17:21 ~/dietforurcle/media (master)$ cd ..
(venv) 17:21 ~/dietforurcle (master)$ cd static
(venv) 17:21 ~/dietforurcle/static (master)$ pwd
/home/kavomain/dietforurcle/static

mkdir - команда для создания папок, создадим static и media в корневой папке проекта, это не принципиальный момент, вы можете вынести их, например, на уровень ниже.
pwd - показывает путь до папки, в которой вы находитесь. Это бывает очень удобно, когда вы сомневаетесь в пути, можете любые пути для настроек проекта проверять этой командой.

WSGI configuration file

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

/var/www/kavomain_pythonanywhere_com_wsgi.py
# +++++++++++ DJANGO +++++++++++
# To use your own django app use code like this:
import os
import sys
#
## assuming your django settings file is at '/home/kavomain/mysite/mysite/settings.py'
## and your manage.py is is at '/home/kavomain/mysite/manage.py'
path = '/home/kavomain/dietforurcle'
if path not in sys.path:
    sys.path.append(path)
#
os.environ['DJANGO_SETTINGS_MODULE'] = 'dietforurcle.settings'
#
## then:
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

В path указывается путь до папки с файлом manage.py.
В os.environ['DJANGO_SETTINGS_MODULE'] указывается путь до файла settings.py относительно пути из переменной path через точечную нотацию. dietforurcle.settings означает, что путь до settings.py - /home/kavomain/dietforurcle/dietforurcle

Проверить этот путь можно также во вкладке Files вашего кабинета. Тут же можно редактировать некоторые файлы при необходимости.

Также вы можете ознакомиться с официальной документацией по деплою django проектов.

settings.py. Перенос базы данных

Воспользуемся возможностью редактирования файлов для редактирования файла settings.py. Также вы можете редактировать файл через Bash, использую редактор vim. Для этого находясь в папке с файлом settings.py введите команду vim settings.py. Откроется файл, находясь в режиме редактирования изменить необходимые настройки. Для того чтобы выйти из vim и сохранить изменения нажмите Esc и введите снизу в командной строке редактора qw! и нажмите Enter.

/home/kavomain/dietforurcle/dietforurcle/settings.py
...
ALLOWED_HOSTS = ['kavomain.pythonanywhere.com', ]
...

STATIC_URL = '/static/'
STATIC_ROOT = '/home/kavomain/dietforurcle/static'

MEDIA_URL = '/media/'
MEDIA_ROOT = '/home/kavomain/dietforurcle/media'

В ALLOWED_HOSTS добавьте адрес вашего проекта и настройки для media и static. Тут же вы можете изменить SECRET_KEY, если вы не изменяли его перед загрузкой github, потому что в таком случае в истории коммитов ваш SECRET_KEY будет виден.

Проект почти готов к запуску.

Bash
(venv) 17:26 ~/dietforurcle (master)$ python manage.py makemigrations
(venv) 17:26 ~/dietforurcle (master)$ python manage.py migrate 
(venv) 17:26 ~/dietforurcle (master)$ python manage.py createsuperuser
(venv) 17:26 ~/dietforurcle (master)$ python manage.py collectstatic

Осталось создать и произвести миграции. Создать суперпользователя. И собрать статику, даже если в вашем проекте не используются изображения и стили все равно воспользуйтесь этой командой, потому что статические системные файлы django, например, стили для админки также собираются этой командой.

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

Осталось заняться записями в базе данных. Сейчас сайт имеет стили и текст выводимый не через обращения к базам данных. Если перейти в админку, то мы увидим, что таблицы БД есть, а вот записей - нет. sqlite3 находится в gitignore и никакие записи естественно в проект не перенеслись.
Вы можете добавлять записи через админку и все они будут появляться на сайте, а можете перенести БД с локальной директории на хостинг.

Terminal
(venv) tsarkoilya@tsarkoilya-NBLK-WAX9X:~/kavo/KAVO/dietforurcle$ python manage.py dumpdata --indent 2 > mydata.json
Bash
(venv) 17:29 ~/dietforurcle (master)$ ls
dietforurcle manage.py media menu mydata.json requirements.txt static week
(venv) 17:29 ~/dietforurcle (master)$ python manage.py loaddata mydata.json
Installed 91 object(s) from 1 fixture(s)

Для этого находясь в локальной версии проекта воспользуйтесь командой

python manage.py dumpdata --indent 2 > mydata.json

--indent 2 - настройка отступов в итоговом .json файле, они упрощают чтение файла, если вы собираетесь просматривать его вручную. Если же вам читать его не нужно и вы сразу собираетесь его загружать в проект, то indent можно пропустить. Далее через > записывается название файла и формат .json.

Теперь этот файл нужно перенести в проект, вы можете сделать новый коммит и склонировать проект с новым файлом, но быстрее и проще будет перейти во вкладку Files и кнопкой Upload a file загрузить .json файл с вашей БД к вам в проект. Положите этот файл на одном уровне с manage.py.

И последним шагом будет уже через Bash воспользоваться обратной командой для загрузки БД.

python manage.py loaddata mydata.json

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

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

Проект на pythonanywhere загружен и работает.
dietforurcle доступен в интернете для любых пользователей и сделали мы это абсолютно бесплатно.

Для отправки комментария необходимо авторизоваться



Комментарии

Здесь пока ничего нет...