После того как проекту был придан профессиональный вид, мы развернем его на реальном сервере, чтобы любой пользователь с подключением к Интернету мог работать с приложением. Мы воспользуемся Heroku — веб-платформой, позволяющей управлять развертыванием веб-приложений.
Процесс для системы Windows несколько отличается от процесса в Linux и OS X. Если вы работаете в Windows, обращайте внимание на врезки, указывающие, какие изменения следует внести в вашей системе.
Создание учетной записи Heroku
Чтобы создать учетную запись, откройте сайт https://heroku.com/ и щелкните на одной из регистрационных ссылок. Учетные записи создаются бесплатно, и Heroku предоставляет бесплатный уровень для тестирования проектов в реальных условиях.
Примечание
На бесплатном уровне Heroku существуют свои ограничения (например, количество приложений, которые можно развернуть, и частоту посещения приложения пользователями). Впрочем, эти ограничения достаточно либеральны, чтобы вы могли потренироваться в развертывании приложений без каких-либо затрат.
Установка инструментария Heroku Toolbelt
Чтобы развернуть проект на серверах Heroku и управлять им, вам понадобятся инструменты из пакета Heroku Toolbelt. Чтобы установить новейшую версию Heroku Toolbelt, откройте сайт https://toolbelt.heroku.com/ и выполните указания для своей операционной системы. В них содержится либо однострочная терминальная команда, либо программа установки, которую вы можете загрузить и запустить.
Установка необходимых пакетов
Вам также придется установить ряд пакетов, упрощающих работу проектов Django на реальных серверах. В активной виртуальной среде введите следующие команды:
(ll_env)learning_log$ pip install dj-database-url
(ll_env)learning_log$ pip install dj-static
(ll_env)learning_log$ pip install static3
(ll_env)learning_log$ pip install gunicorn
Обязательно вводите команды по одной, чтобы вы знали, если при установке какого-либо пакета возникнет проблема. Пакет dj-database-url помогает Django взаимодействовать с базой данных, используемой Heroku, пакеты dj-static и static3 позволяют Django правильно управлять статическими файлами, а gunicorn — сервер, способный предоставлять доступ к приложениям в реальной среде. (Статические файлы содержат стилевые правила и файлы JavaScript.)
Примечание
Некоторые из необходимых пакетов могут не установиться в Windows, но не огорчайтесь, если при попытке установки вы получите сообщение об ошибке. Важнее добиться того, чтобы пакеты были установлены Heroku для развернутого приложения, а этим мы займемся в следующем разделе.
Создание списка пакетов с файлом requirements.txt
Heroku необходимо знать, от каких пакетов зависит наш проект, поэтому мы воспользуемся pip для построения файла со списком. Оставаясь в активной виртуальной среде, введите следующую команду:
(ll_env)learning_log$ pip freeze >requirements.txt
Команда freeze приказывает pip записать имена всех пакетов, в настоящее время установленных в системе, в файл requirements.txt. Откройте файл requirements.txt и просмотрите пакеты и номера версий, установленных в вашей системе (возможно, пользователи Windows не увидят какие-то строки):
requirements.txt
Django==1.8.4
dj-database-url==0.3.0
dj-static==0.0.6
django-bootstrap3==6.2.2
gunicorn==19.3.0
static3==0.6.1
Приложение Learning Log уже зависит от шести разных пакетов с конкретными номерами версий, поэтому для его правильной работы требуется конкретная конфигурация среды. При развертывании Learning Log Heroku устанавливает все пакеты, перечисленные в requirements.txt, и создает среду с теми же пакетами, которые мы используем локально. По этой причине разработчик может быть уверен в том, что развернутый проект будет работать точно так же, как в его локальной системе. Вы поймете, насколько это полезно, когда начнете строить и вести в своей системе несколько разных проектов.
Затем необходимо добавить в список пакет psycopg2, который помогает Heroku управлять базой данных. Откройте файл requirements.txt и добавьте строку psycopg2>=2.6.1. Эта строка устанавливает версию 2.6.1 пакета psycopg2 (или более новую версию, если она доступна):
requirements.txt
Django==1.8.4
dj-database-url==0.3.0
dj-static==0.0.6
django-bootstrap3==6.2.2
gunicorn==19.3.0
static3==0.6.1
psycopg2>=2.6.1
Если какие-либо пакеты не установлены в вашей системе, добавьте их. В итоге ваш файл requirements.txt должен включать каждый из приведенных выше пакетов. Если пакет входит в список вашей системы, но номер версии отличается от приведенной, оставьте версию вашей системы.
Примечание
Если вы работаете в системе Windows, убедитесь в том, что ваша версия requirements.txt соответствует приведенному списку, — независимо от того, какие пакеты вам удалось установить в вашей системе.
Назначение исполнительной среды Python
Если вы не укажете версию Python, то Heroku будет использовать собственную версию Python по умолчанию. Убедитесь в том, что Heroku использует ту же версию Python, которая используется у вас. В активной виртуальной среде введите команду python --version:
(ll_env)learning_log$ python --version
Python 3.5.0
В этом примере я использую Python 3.5.0. Создайте новый файл с именем runtime.txt в одном каталоге с файлом manage.py и введите следующую команду:
runtime.txt
python-3.5.0
Этот файл должен содержать одну строку с версией Python, заданной точно в показанном формате: python в нижнем регистре, затем дефис и номер версии из трех частей.
Примечание
Если вы получите сообщение об ошибке, в котором сказано, что запрашиваемая исполнительная среда Python недоступна, откройте страницу https://devcenter.heroku.com/ и щелкните на ссылке Python, затем найдите ссылку Specifying a Python Runtime. Просмотрите текст статьи, найдите доступные варианты исполнительной среды и выберите тот вариант, который ближе всего к вашей версии Python.
Изменение файла settings.py для Heroku
Затем в конец файла settings.py необходимо добавить раздел для определения настроек, предназначенных конкретно для среды Heroku:
settings.py
...
# Настройки для django-bootstrap3
BOOTSTRAP3 = {
'include_jquery': True,
}
# Настройки Heroku
(1) if os.getcwd() == '/app':
(2) . .import dj_database_url
. .DATABASES = {
. . . .'default': dj_database_url.config(default='postgres://localhost')
. .}
. .
. .# Поддержка заголовка 'X-Forwarded-Proto' для request.is_secure().
(3) . .SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
. .
. .# Разрешены все заголовки хостов.
(4) . .ALLOWED_HOSTS = ['*']
. .# Конфигурация статических ресурсов
(5) . .BASE_DIR = os.path.dirname(os.path.abspath(__file__))
. .STATIC_ROOT = 'staticfiles'
. .STATICFILES_DIRS = (
. . . .os.path.join(BASE_DIR, 'static'),
. .)
В точке (1) используется функция getcwd(), которая возвращает текущий рабочий каталог, из которого был запущен файл. В схеме развертывания Heroku таким каталогом всегда является /app. При локальном развертывании каталог обычно совпадает с именем папки проекта (learning_log в нашем случае). Проверка if гарантирует, что настройки в этом блоке будут применяться только при развертывании проекта в Heroku. Такая структура позволяет создать один файл настроек, который подойдет как для локальной среды разработки, так и для развертывания на сервере.
В точке (2) импортируется модуль dj_database_url, упрощающий настройку базы данных в Heroku. Heroku использует PostgreSQL (или Postgres) — более мощную базу данных, чем SQLite; эти параметры настраивают проект для работы с Postgres в среде Heroku. Остальные настройки обеспечивают поддержку запросов HTTPS (3), правильный доступ к проекту с URL Heroku (4) и правильное размещение статических файлов на Heroku (5).
Создание файла Procfile для запуска процессов
Файл Procfile сообщает Heroku, какие процессы должны запускаться для правильной работы проекта. Это однострочный файл, который должен быть сохранен под именем Procfile (символ P верхнего регистра, без расширения) в одном каталоге с файлом manage.py. Содержимое Procfile выглядит так:
Procfile
web: gunicorn learning_log.wsgi --log-file -
Эта строка приказывает Heroku использовать для приложения сервер gunicorn, а при запуске приложения загрузить настройки из файла learning_log/wsgi.py. Флаг log-file сообщает Heroku, какие события должны регистрироваться в журнале.
Изменение файла wsgi.py для Heroku
Также необходимо внести изменения в файл wsgi.py для Heroku, потому что конфигурация для Heroku несколько отличается от той, которая использовалась ранее:
wsgi.py
...
import os
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "learning_log.settings")
application = Cling(get_wsgi_application())
Мы импортируем приложение Cling, упрощающее организацию доступа к статическим файлам, и используем его для запуска приложения. Этот код также будет работать локально, так что помещать его в блок if не нужно.
Создание каталога для статических файлов
В среде Heroku Django собирает все статические файлы и размещает их в одном месте для эффективного управления. Для этих статических файлов мы создадим специальный каталог. В каталоге learning_log, с которыми работали ранее, находится другой каталог с именем learning_log. В этом вложенном каталоге создайте новый подкаталог с именем static; таким образом, полный путь имеет вид learning_log/learning_log/static/. Также необходимо создать временный файл-«заполнитель» в этом каталоге, потому что при загрузке на Heroku пустые каталоги не включаются в проект. Создайте в каталоге static/ файл с именем placeholder.txt:
placeholder.txt
Этот файл необходим для включения в проект каталога learning_log/static/.
Django собирает статические файлы и помещает их в каталог learning_log/static/.
В этом тексте нет ничего особенного; он просто напоминает, почему этот файл был включен в проект.
Локальное использование сервера gunicorn
Если вы используете Linux или OS X, вы можете попробовать использовать сервер gunicorn локально, прежде чем развертывать его на сервере Heroku. В активной виртуальной среде выполните команду heroku local, чтобы запустить процессы, определенные в Procfile:
(ll_env)learning_log$ heroku local
Installing Heroku Toolbelt v4... done
...
forego | starting web.1 on port 5000
(1) web.1 | [2015-08-13 22:00:45 -0800] [12875] [INFO] Starting gunicorn 19.3.0
(2)web.1 | [2015-08-13 22:00:45 -0800] [12875] [INFO] Listening at:
. .http://0.0.0.0:5000 (12875)
(3)web.1 | [2015-08-13 22:00:45 -0800] [12878] [INFO] Booting worker with pid: 12878
При первом выполнении heroku local будет установлен набор пакетов из Heroku Toolbelt. Из выходных данных видно, что в приведенном примере сервер gunicorn был запущен с идентификатором процесса 12875 (1) . В точке (2) gunicorn прослушивает запросы на порте 5000. Кроме того, gunicorn запускает рабочий процесс (12878), который будет помогать в обслуживании запросов (3).
Откройте адрес http://localhost:5000/ и убедитесь в том, что все работает; домашняя страница Learning Log должна выглядеть так же, как она выглядит при использовании сервера Django (runserver). Нажмите Ctrl+C, чтобы остановить процессы, запущенные командой heroku local. При локальной разработке продолжайте использовать runserver.
Примечание
В системе Windows gunicorn работать не будет; пропустите этот шаг, если вы используете Windows. Это не повлияет на возможность развертывания проекта в Heroku.
Использование Git для управления файлами проекта
Если вы дочитали главу 17, то вы уже знаете, что Git — программа контроля версий, которая позволяет создать «мгновенный снимок» состояния кода проекта при реализации каждой новой функции. Это позволяет легко вернуться к последнему работоспособному состоянию проекта при возникновении каких-либо проблем (например, если в ходе работы над новой функцией была случайно внесена ошибка).
Если в вашем проекте используется Git, это означает, что вы можете работать над новой функциональностью, не беспокоясь о том, чтобы ничего не нарушить. Развертывая проект на сервере, вы должны убедиться в том, что вы развертываете работоспособную версию проекта. Если вы захотите больше узнать о Git и контроле версий, обращайтесь к приложению Г.
Установка Git
Git входит в инструментарий Heroku Toolbelt, так что пакет Git уже должен быть установлен в вашей системе. Однако система Git будет недоступна в терминальных окнах, которые были открыты перед установкой Heroku Toolbelt, поэтому откройте новое терминальное окно и введите команду git --version:
(ll_env)learning_log$ git --version
git version 2.5.0
Если вы получите сообщение об ошибке, обращайтесь к инструкциям по установке Git в приложении Г.
Настройка Git
Git следит за тем, кто внес изменения в проект, даже в том случае, если над проектом работает только один человек. Для этого Git необходимо знать ваше имя пользователя и адрес электронной почты. Имя пользователя ввести обязательно, но ничто не мешает вам ввести вымышленный адрес электронной почты для учебных проектов:
(ll_env)learning_log$ git config --global user.name "ehmatthes"
(ll_env)learning_log$ git config --global user.email "eric@example.com"
Если вы забудете об этом шаге, Git запросит у вас эту информацию при первом закреплении.
Игнорирование файлов
Нам не нужно, чтобы система Git отслеживала все файлы в проекте, поэтому мы прикажем Git игнорировать некоторые файлы. Создайте файл с именем .gitignore в папке с файлом manage.py. Обратите внимание: имя файла начинается с точки, а файл не имеет расширения. Содержимое .gitignore выглядит так:
.gitignore
ll_env/
__pycache__/
*.sqlite3
Мы приказываем Git игнорировать весь каталог ll_env, потому что мы можем автоматически воссоздать его в любой момент. Также в системе контроля не отслеживается каталог __pycache__ с файлами .pyc, которые создаются автоматически, когда Django выполняет файлы .py. Мы не отслеживаем изменения в локальной базе данных, потому что так поступать вообще нежелательно: если на сервере будет использоваться SQLite, вы можете случайно переписать «живую» базу данных локальной тестовой базой данных при отправке проекта на сервер.
Примечание
Если вы используете Python 2.7, замените __pycache__ на *.pyc, потому что Python 2.7 не создает каталог __pycache__.
Закрепление состояния проекта
Чтобы инициализировать репозиторий Git для Learning Log, добавьте все необходимые файлы в репозиторий и закрепите исходное состояние проекта. Вот как это делается:
(1) (ll_env)learning_log$ git init
Initialized empty Git repository in /home/ehmatthes/pcc/learning_log/.git/
(2)(ll_env)learning_log$ git add .
(3)(ll_env)learning_log$ git commit -am "Ready for deployment to heroku."
[master (root-commit) dbc1d99] Ready for deployment to heroku.
43 files changed, 746 insertions(+)
create mode 100644 .gitignore
create mode 100644 Procfile
--snip--
create mode 100644 users/views.py
(4)(ll_env)learning_log$ git status
# On branch master
nothing to commit, working directory clean
(ll_env)learning_log$
В точке (1) вводится команда git init, которая инициализирует пустой репозиторий в каталоге, содержащем Learning Log. В точке (2) команда git add. добавляет все файлы (кроме игнорируемых) в репозиторий (не забудьте точку). В точке (3) вводится команда git commit -am сообщение: флаг -a приказывает Git включить все измененные файлы в закрепленное состояние, а флаг -m приказывает Git сохранить сообщение в журнале.
Вывод команды git status (4) сообщает, что текущей является главная ветвь, а рабочий каталог пуст. Этот статус должен выводиться каждый раз, когда вы отправляете свой проект на Heroku.
Отправка проекта
Наконец-то все готово для отправки проекта на сервер Heroku. В активном терминальном сеансе введите следующие команды:
(1) (ll_env)learning_log$ heroku login
Enter your Heroku credentials.
Email: eric@example.com
Password (typing will be hidden):
Logged in as eric@example.com
(2)(ll_env)learning_log$ heroku create
Creating afternoon-meadow-2775... done, stack is cedar-14
https://afternoon-meadow-2775.herokuapp.com/ |
. .https://git.heroku.com/afternoon-meadow-2775.git
Git remote heroku added
(3)(ll_env)learning_log$ git push heroku master
...
remote: -----> Launching... done, v6
(4)remote: . . . .https://afternoon-meadow-2775.herokuapp.com/ deployed to Heroku
remote: Verifying deploy.... done.
To https://git.heroku.com/afternoon-meadow-2775.git
bdb2a35..62d711d master -> master
(ll_env)learning_log$
Сначала войдите на сервер Heroku в терминальном сеансе с именем пользователя и паролем, использованными при создании учетной записи на https://heroku.com/ (1) . Затем прикажите Heroku построить пустой проект (2). Heroku генерирует имя, состоящее из двух слов и числа; позднее вы сможете его изменить. Затем вводится команда git push heroku master (3), которая приказывает Git отправить главную ветвь проекта в репозиторий, только что созданный Heroku. После этого Heroku строит проект на своих серверах с использованием этих файлов. В точке (4) указывается URL, который будет использоваться для обращения к развернутому проекту.
После ввода этих команд проект развернут, но еще не настроен полностью. Чтобы проверить, что серверный процесс был запущен правильно, введите команду heroku ps:
(ll_env)learning_log$ heroku ps
(1) Free quota left: 17h 40m
(2)=== web (Free): `gunicorn learning_log.wsgi __log-file -`
web.1: up 2015/08/14 07:08:51 (~ 10m ago)
(ll_env)learning_log$
В выходных данных указано, сколько еще времени проект может оставаться активным на протяжении следующих 24 часов (1) . На момент написания книги Heroku позволяет бесплатно развернутым проектам оставаться активными до 18 часов за 24-часовой период. При нарушении этого лимита отображается стандартная серверная страница ошибки; вскоре мы изменим ее. В точке (2) запускается процесс, определенный в Procfile.
Теперь мы можем открыть приложение в браузере командой heroku open:
(ll_env)learning_log$ heroku open
Opening afternoon-meadow-2775... done
Команда избавляет вас от необходимости открывать браузер и вводить URL, который вы получили от Heroku, но при желании сайт можно открыть и так. Вы увидите домашнюю страницу Learning Log с правильным оформлением. Впрочем, с приложением еще работать нельзя, потому что база данных не подготовлена.
Примечание
Процесс развертывания приложений на серверах Heroku время от времени изменяется. Если у вас возникнут неразрешимые проблемы, обращайтесь к документации Heroku за помощью. Откройте страницу https://devcenter.heroku.com/ и щелкните на ссылке Python, затем найдите ссылку Getting Started with Django. Если вы не понимаете то, что там написано, обратитесь к рекомендациям в приложении В.
Подготовка базы данных в Heroku
Вы должны выполнить команду migrate, чтобы подготовить базу данных и применить все миграции, сгенерированные в ходе разработки. Для выполнения команд Django и Python в проектах Heroku используется команда heroku run. Пример выполнения команды migrate в среде разработки Heroku:
(1) (ll_env)learning_log$ heroku run python manage.py migrate
(2)Running `python manage.py migrate` on afternoon-meadow-2775... up, run.2435
...
(3)Running migrations:
...
Applying learning_logs.0001_initial... OK
Applying learning_logs.0002_entry... OK
Applying learning_logs.0003_topic_user... OK
Applying sessions.0001_initial... OK
(ll_env)learning_log$
Сначала мы вводим команду heroku run python manage.py migrate (1) . Heroku создает терминальный сеанс для выполнения команды migrate (2). В точке (3) Django применяет миграции по умолчанию, а также миграции, сгенерированные в ходе разработки Learning Log.
Теперь при обращении к развернутому приложению вы сможете использовать его так же, как это делалось в локальной системе. Однако при этом вы не увидите никакие данные, введенные при локальном развертывании, потому что мы не скопировали данные на сервер. Это обычная практика: локальные данные почти никогда не копируются на сервер, потому что они чаще всего являются тестовыми.
Если вы перешлете ссылку на Heroku, получатель сможет работать с вашей версией приложения Learning Log. В следующем разделе мы выполним еще несколько операций, чтобы завершить процесс развертывания и подготовиться к дальнейшей разработке Learning Log.
Доработка развернутого приложения
В этом разделе мы доработаем развернутое приложение и создадим суперпользователя (так же, как это было сделано в локальной версии). Заодно мы повысим уровень защиты проекта, переведя настройку отладочного режима DEBUG в состояние False, чтобы пользователи не получали в сообщениях об ошибке дополнительной информации, которая может использоваться для проведения атак на сервер.
Создание суперпользователя в Heroku
Вы уже видели, что для выполнения одиночных команд может использоваться команда heroku run. Однако команды также можно выполнять, открыв терминальный сеанс Bash при подключении к серверу Heroku командой heroku run bash. Bash — язык, который работает во многих терминалах Linux. Мы используем терминальный сеанс Bash для создания суперпользователя, чтобы иметь возможность обратиться к административному сайту в развернутом приложении:
(ll_env)learning_log$ heroku run bash
Running `bash` on afternoon-meadow-2775... up, run.6244
(1) ~ $ ls
learning_log learning_logs manage.py Procfile requirements.txt runtime.txt
users
staticfiles
(2)~ $ python manage.py createsuperuser
Username (leave blank to use 'u41907'): ll_admin
Email address:
Password:
Password (again):
Superuser created successfully.
(3)~ $ exit
exit
(ll_env)learning_log$
В точке (1) команда ls выводит информацию о файлах и каталогах, существующих на сервере; это те же файлы, которые присутствуют в нашей локальной системе. В этой файловой системе можно перемещаться так же, как и в любой другой.
Примечание
Пользователи Windows должны использовать те же команды (например, ls вместо dir), потому что они работают с терминалом Linux через удаленное подключение.
В точке (2) выполняется команда создания суперпользователя. Она выдает тот же вывод, который был получен в локальной системе при создании суперпользователя в главе 18. После того как создание суперпользователя в терминальном сеансе будет завершено, введите команду exit для возвращения к терминальному сеансу локальной системы (3).
Теперь вы можете добавить /admin/ в конец URL-адреса развернутого приложения, чтобы войти на административный сайт. У меня этот URL-адрес имеет вид https://afternoon-meadow-2775.herokuapp.com/admin/.
Если другие пользователи уже начали работать с вашим проектом, учтите, что вам будут доступны все их данные! Относитесь к конфиденциальности серьезно, и пользователи начнут доверять вам свои данные.
Создание удобного URL-адреса на Heroku
Вероятно, вы бы предпочли использовать более удобные и запоминающиеся URL-адреса, чем https://afternoon-meadow-2775.herokuapp.com/. Чтобы переименовать приложение, достаточно одной команды:
(ll_env)learning_log$ heroku apps:rename learning-log
Renaming afternoon-meadow-2775 to learning-log... done
https://learning-log.herokuapp.com/ | https://git.heroku.com/learning-log.git
Git remote heroku updated
(ll_env)learning_log$
Имя может содержать буквы, цифры и дефисы и выбирается произвольно (при условии, что никто другой еще не занял это имя). Развернутая версия теперь доступна по адресу https://learning-log.herokuapp.com/. По предыдущему URL-адресу проект теперь недоступен; команда apps:rename полностью перемещает проект на новый URL-адрес.
Примечание
При развертывании проекта на бесплатном сервисе Heroku переводит развернутое приложение в спящий режим, если оно не получало запросов в течение определенного периода времени или было слишком активным для бесплатного уровня. При первом обращении к сайту после перехода в спящий режим загрузка займет больше времени, но последующие запросы будут обрабатываться быстрее. Такой подход позволяет Heroku предоставлять бесплатное развертывание.
Безопасность проекта
В текущем варианте развертывания проекта существует одна очевидная проблема: настройка DEBUG=True в файле settings.py, включающая вывод отладочных сообщений при возникновении ошибок. Страницы ошибок Django предоставляют критическую отладочную информацию при разработке проекта, но они также дают слишком много информации хакерам, если оставить их включенными на рабочем сервере. Также необходимо проследить за тем, чтобы никто не мог получать информацию или перенаправлять запросы, выдавая себя за хост проекта.
Изменим файл settings.py, чтобы сообщения об ошибках выводились локально, но не в развернутой версии:
settings.py
...
# Настройки Heroku
if os.getcwd() == '/app':
...
# Поддержка заголовка 'X-Forwarded-Proto' для request.is_secure().
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
. .
. .# Хостом проекта может быть только Heroku.
(1) . .ALLOWED_HOSTS = ['learning-log.herokuapp.com']
(2) . .DEBUG = False
# Конфигурация статических ресурсов.
...
Необходимо внести только два изменения: в точке (1) изменяется настройка ALLOWED_HOSTS, чтобы хостом проекта мог быть только сервер Heroku. Используйте имя своего приложения — сгенерированное Heroku (как afternoon-meadow-2775.herokuapp.com в нашем примере) или выбранное вами. В точке (2) переменной DEBUG присваивается значение False, чтобы при возникновении ошибок не раскрывалась конфиденциальная информация.
Закрепление и отправка изменений
Теперь изменения, внесенные в settings.py, необходимо закрепить в репозитории Git, а затем отправить их на Heroku. Следующий терминальный сеанс показывает, как это делается:
(1) (ll_env)learning_log$ git commit -am "Set DEBUG=False for Heroku."
[master 081f635] Set DEBUG=False for Heroku.
1 file changed, 4 insertions(+), 2 deletions(-)
(2)(ll_env)learning_log$ git status
# On branch master
nothing to commit, working directory clean
(ll_env)learning_log$
Мы вводим команду git commit с коротким, но содержательным сообщением (1) . Напомню, что флаг -am обеспечивает закрепление всех изменившихся файлов и регистрацию сообщения в журнале. Git видит, что изменился один файл, и закрепляет изменение в репозитории.
В точке (2) из статусной информации видно, что мы работаем с главной ветвью репозитория, а новые изменения для закрепления отсутствуют. Очень важно проверять статусную информацию перед отправкой на Heroku. Если вы не видите сообщение, значит, некоторые изменения не были закреплены, и они не будут отправлены на сервер. Попробуйте снова ввести команду commit, а если вы не уверены в том, как решить проблему, — прочитайте приложение Г, чтобы лучше понять, как работать с Git.
Теперь отправим обновленный репозиторий на Heroku:
(ll_env)learning_log$ git push heroku master
...
remote: -----> Python app detected
remote: -----> Installing dependencies with pip
...
remote: -----> Launching... done, v8
remote: . . . .https://learning-log.herokuapp.com/ deployed to Heroku
remote: Verifying deploy.... done.
To https://git.heroku.com/learning-log.git
4c9d111..ef65d2b master -> master
(ll_env)learning_log$
Heroku видит, что репозиторий обновился, и заново строит проект, чтобы все изменения были учтены. База данных при этом не воссоздается, поэтому выполнять migrate для этого обновления не придется.
Чтобы убедиться в том, что развертывание стало более безопасным, введите URL проекта с расширением, которое не было определено. Например, попробуйте открыть страницу http://learning-log.herokuapp.com/letmein/. Должна появиться обобщенная страница, которая не сообщает никакой конкретной информации о проекте. Если же вы попробуете применить тот же запрос с локальной версией Learning Log по адресу http://localhost:8000/letmein/, должна появиться стандартная страница ошибки Django. Получается именно то, что нужно: вы будете получать содержательные сообщения об ошибках в процессе разработки проекта, но оградите пользователей от критической информации о коде проекта.
Создание специализированных страниц ошибок
В главе 19 мы настроили приложение Learning Log так, чтобы при запросе темы или записи, которая ему не принадлежит, пользователь получал ошибку 404. Вероятно, вы также сталкивались с примерами ошибок 500 (внутренние ошибки). Ошибка 404 обычно означает, что код Django правилен, но запрашиваемый объект не существует; ошибка 500 обычно означает, что в написанном вами коде существует ошибка (например, ошибка в функции из views.py). В настоящее время Django возвращает одну обобщенную страницу ошибки в обеих ситуациях, но мы можем написать собственные шаблоны страниц ошибок 404 и 500, которые соответствуют общему оформлению Learning Log. Эти шаблоны должны находиться в корневом каталоге шаблонов.
Создание пользовательских шаблонов
В папке learning_log/learning_log создайте новую папку с именем templates. Затем создайте новый файл с именем 404.html:
404.html
{% extends "learning_logs/base.html" %}
{% block header %}
. .
The item you requested is not available. (404)
{% endblock header %}
Этот простой шаблон предоставляет ту же информацию, что и обобщенная страница ошибки 404, но его оформление соответствует остальным страницам сайта.
Создайте другой файл с именем 500.html:
500.html
{% extends "learning_logs/base.html" %}
{% block header %}
. .
There has been an internal error. (500)
{% endblock header %}
Новые файлы потребуют небольших изменений в settings.py.
settings.py
...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
. . . .'DIRS': [os.path.join(BASE_DIR, 'learning_log/templates')],
'APP_DIRS': True,
...
},
]
...
Это изменение приказывает Django искать шаблоны страниц ошибок в корневом каталоге шаблонов.
Локальный просмотр страниц ошибок
Если вы хотите посмотреть, как будут выглядеть страницы ошибок, в своей системе перед отправкой на сервер Heroku, вам сначала придется установить в локальных настройках режим Debug=False, чтобы подавить выдачу отладочных страниц Django по умолчанию. Для этого внесите следующие изменения в settings.py (убедитесь в том, что вы работаете в части settings.py, относящейся к локальной среде, — а не той, которая относится к Heroku):
settings.py
...
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = ['localhost']
...
Если DEBUG присвоено значение False, в ALLOWED_HOSTS должен быть указан хотя бы один хост. Теперь запросите тему или запись, которая вам не принадлежит, чтобы увидеть страницу ошибки 404. Затем запросите несуществующий URL-адрес (например, localhost:8000/letmein/), чтобы увидеть страницу ошибки 500.
Завершив проверку, верните DEBUG значение True, чтобы продолжить разработку Learning Log. (Проследите за тем, чтобы настройка DEBUG содержала False в разделе settings.py, относящемся к развертыванию в среде Heroku.)
Примечание
Страница ошибки 500 не содержит никакой информации о текущем пользователе, потому что Django не включает контекстную информацию в ответ при возникновении ошибки сервера.
Отправка изменений на Heroku
Теперь необходимо закрепить изменения в шаблоне и отправить их на Heroku:
(1) (ll_env)learning_log$ git add .
(2)(ll_env)learning_log$ git commit -am "Added custom 404 and 500 error pages."
3 files changed, 15 insertions(+), 10 deletions(-)
create mode 100644 learning_log/templates/404.html
create mode 100644 learning_log/templates/500.html
(3)(ll_env)learning_log$ git push heroku master
...
remote: Verifying deploy.... done.
To https://git.heroku.com/learning-log.git
2b34ca1..a64d8d3 master -> master
(ll_env)learning_log$
В точке (1) выдается команда git add ., потому что в проекте были созданы новые файлы, и теперь нужно приказать Git начать отслеживание этих файлов. Затем мы закрепляем изменения (2) и отправляем обновленный проект на Heroku (3). Теперь страницы ошибок имеют такое же оформление, как остальные страницы сайта, а приложение выглядит более профессионально при возникновении ошибок.
Использование метода get_object_or_404()
На данный момент, если пользователь вручную запрашивает несуществующую тему или запись, он получает ошибку сервера 500. Django пытается отобразить страницу, но не располагает достаточной информацией для этого, что приводит к ошибке 500. Такая ситуация более точно обрабатывается как ошибка 404, и это поведение можно реализовать при помощи вспомогательной функции Django get_object_or_404(). Эта функция пытается получить запрошенный объект из базы данных, а если этот объект не существует — инициирует исключение 404. Мы импортируем эту функцию в views.py и используем ее вместо get():
views.py
...
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect, Http404
...
@login_required
def topic(request, topic_id):
"""Выводит одну тему и все ее записи."""
. .topic = get_object_or_404(Topic, id=topic_id)
# Проверка того, что тема принадлежит текущему пользователю.
...
Теперь при запросе несуществующей темы (например, http://localhost:8000/topics/999999/) появляется страница ошибки 404. Чтобы развернуть это изменение, выполните закрепление и отправьте проект на Heroku.
Текущая разработка
Возможно, вы захотите продолжить разработку Learning Log после исходной отправки данных на сервер или создать и развернуть собственные проекты. Существует достаточно четко определенный процесс обновления проектов.
Сначала все необходимые изменения вносятся в локальный проект. Если изменения приводят к появлению новых файлов, добавьте эти файлы в репозиторий Git командой git add . (не забудьте точку в конце команды). Эта команда необходима для любого изменения, требующего миграции базы данных, потому что для каждой миграции генерируется новый файл миграции.
Затем закрепите изменения в репозитории командой git commit -am "сообщение". Отправьте изменения на Heroku командой git push heroku master. Если вы провели локальную миграцию базы данных, также необходимо провести миграцию и для базы данных развернутого приложения. Либо используйте одноразовую команду heroku run python manage.py migrate, либо откройте удаленный терминальный сеанс командой heroku run bash и выполните команду python manage.py migrate. Затем посетите свой проект и убедитесь в том, что предполагаемые изменения вступили в силу.
В этом процессе легко допустить ошибку, так что не удивляйтесь, если что-то пойдет не так. Если код не работает, проанализируйте то, что было сделано, и попробуйте найти ошибку. Если найти ошибку не удается или вы не можете понять, как ее отменить, обращайтесь к рекомендациям в приложении В. Не стесняйтесь обращаться за помощью: все остальные учились строить проекты и задавали те же вопросы, которые возникнут и у вас, так что вы наверняка найдете кого-нибудь, кто согласится помочь. Решение всех возникающих проблем поможет развивать ваши навыки до того момента, когда вы начнете строить содержательные, надежные проекты и отвечать на вопросы других людей.
Параметр SECRET_KEY
Django использует значение настройки SECRET_KEY из файла settings.py для реализации некоторых протоколов безопасности. В нашем проекте файл настроек был закреплен с включением настройки SECRET_KEY. Для учебного проекта этого достаточно, но на реальном сайте с настройкой SECRET_KEY следует действовать более осторожно. Если вы строите проект, предназначенный для реальной эксплуатации, обязательно изучите вопрос, как повысить безопасность настройки SECRET_KEY.
Удаление проекта с Heroku
Очень полезно многократно отработать процесс развертывания на одном проекте или серии малых проектов, чтобы получить представление о развертывании. Однако вы должны знать, как удалить проект после развертывания. Heroku также может ограничивать количество бесплатно развернутых проектов, и загромождать учетную запись учебными проектами нежелательно. Войдите на веб-сайт Heroku (https://heroku.com/), и вы будете перенаправлены на страницу со списком проектов. Щелкните на проекте, который нужно удалить; открывается новая страница с информацией о проекте. Щелкните на ссылке Settings, прокрутите список и найдите ссылку для удаления проекта. Отменить удаление не удастся, поэтому Heroku предложит подтвердить удаление, для чего вам нужно будет вручную ввести имя проекта. Если вы предпочитаете работать в терминальном режиме, проект также можно удалить командой destroy:
(ll_env)learning_log$ heroku apps:destroy --app имя_приложения
Здесь имя_приложения — имя вашего проекта (например, afternoon-meadow-2775 или learning-log, если проект был переименован). Вам также будет предложено снова ввести имя проекта, чтобы подтвердить удаление.
Примечание
При удалении проекта на Heroku с локальной версией проекта ничего не происходит. Если никто не использовал ваш развернутый проект и вы просто отрабатываете процесс развертывания, ничто не мешает вам удалить свой проект на Heroku и развернуть его заново.
Упражнения
20-3. Блог в Интернете: разверните проект Blog, над которым вы работали ранее, на сервере Heroku. Проследите за тем, чтобы настройка DEBUG имела значение False, и измените настройку ALLOWED_HOSTS, чтобы развернутая копия была абсолютно безопасной.
20-4. Больше 404: функцию get_object_or_404() также следует применять в представлениях new_entry() и edit_entry(). Внесите изменения, протестируйте их на URL-адресе вида http://localhost:8000/new_entry/99999/ и убедитесь в том, что при этом выводится ошибка 404.
20-5. Расширенное приложение Learning Log: добавьте простую функцию в Learning Log (например, вывод расширенной информации о проекте на домашней странице) и отправьте изменение в развернутую копию. Затем попробуйте внести более сложное изменение — например, чтобы пользователь мог назначить тему общедоступной. Для этого в модель Topic добавляется атрибут с именем public (по умолчанию он должен быть равен False), а на страницу new_topic — элемент формы, позволяющий превратить личную тему в общедоступную. После этого проведите миграцию проекта и переработайте файл views.py, чтобы любая общедоступная тема также была видимой и для пользователей, не прошедших аутентификацию. Не забудьте провести миграцию базы данных после отправки изменений на Heroku.