Развертывание приложения Django на Heroku: можно ли вручную установить переменные среды в файле .env? Нужно ли мне устанавливать такие инструменты, как autoenv, heroku-config?

Моя цель:

Я намерен следовать методологии «Двенадцатифакторного приложения» при создании моего приложения Django на Heroku.

Вступление:

Я следую краткому руководству по началу работы с Django на Heroku. На данный момент у меня следующая структура каталогов:

~/Projects/
    hellodjango_rep/
        .env (empty)
        .git
        .gitignore
        Procfile
        requirements.txt
        hellodjango/
            manage.py
            hellodjango/
                __init__.py
                settings/
                urls.py
                wsgi.py

Я установил django-toolbelt, создал свое простое приложение Django, запустил процесс в моем Procfile ... Казалось, все работает нормально, но проблемы начались, когда я настроил приложение для среды Heroku и добавил:

import dj_database_url
DATABASES['default'] =  dj_database_url.config()

в конец моего файла settings.py.

Я отправил репозиторий своего приложения в Heroku, успешно $ heroku open зашел в приложение в браузере, но локально: dj_database_url.config() вернул пустой словарь.

Локально:

OS X 10.8.4
pip == 1.4.1
virtualenv == 1.10.1
virtualenvwrapper == 4.1.1
wsgiref == 0.1.2
Postgres.app, работающий на порту 5432

Переменные среды:

mac-pol:hellodjango_rep oubiga$ python
>>> import os
>>> os.environ

{
  'PROJECT_HOME': '/Users/oubiga/Projects'... 
  'PATH': '/usr/local/heroku/bin:/usr/local/share/python:/usr/local/bin:/Applications/Postgres.app/Contents/MacOS/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/git/bin'... 
  'HOME': '/Users/oubiga'... 
  'WORKON_HOME': '/Users/oubiga/Envs'... 
  'VIRTUALENVWRAPPER_HOOK_DIR': '/Users/oubiga/Envs'... 
  'PWD': '/Users/oubiga/Projects/hellodjango_rep'
}

hellodjango_venv:

Django == 1.5.2
dj-database-url == 0.2.2
dj-static == 0.0.5
django-toolbelt == 0.0.1
gunicorn == 18.0
psycopg2 == 2.5.1
статический == 0.4

Вот что у меня в файле wsgi.py:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hellodjango.hellodjango.settings")
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
application = Cling(get_wsgi_application())

Вот что у меня есть в моем файле manage.py:

import os
import sys
if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hellodjango.settings")
    from django.core.management import execute_from_command_line
    execute_from_command_line(sys.argv)

Вот что у меня в Procfile:

web: gunicorn hellodjango.hellodjango.wsgi  

Переменные среды:

(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ python hellodjango/manage.py shell
>>> import os
>>> os.environ 


{
  'PROJECT_HOME': '/Users/oubiga/Projects'... 
  'PATH': '/Users/oubiga/Envs/hellodjango_venv/bin:/usr/local/heroku/bin:/usr/local/share/python:/usr/local/bin:/Applications/Postgres.app/Contents/MacOS/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/git/bin', 
  'HOME': '/Users/oubiga'... 
  'WORKON_HOME': '/Users/oubiga/Envs'... 
  'VIRTUAL_ENV': '/Users/oubiga/Envs/hellodjango_venv'...
  'VIRTUALENVWRAPPER_HOOK_DIR': '/Users/oubiga/Envs'... 
  'PWD': '/Users/oubiga/Projects/hellodjango_rep'... 
  'DJANGO_SETTINGS_MODULE': 'hellodjango.settings'
}

На Heroku:

Переменные среды:

(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ heroku run python hellodjango/manage.py shell
>>> import os
>>> os.environ

{
  'DATABASE_URL': 'postgres://dbuser:[email protected]:5432/dbname', 
  'HEROKU_POSTGRESQL_ORANGE_URL': 'postgres://dbuser:[email protected]:5432/dbname', 
  'LIBRARY_PATH': '/app/.heroku/vendor/lib', 'PWD': '/app'... 
  'DJANGO_SETTINGS_MODULE': 'hellodjango.settings', 
  'PYTHONHOME': '/app/.heroku/python'... 
  'PYTHONPATH': '/app/'... 
  'DYNO': 'run.9068', 
  'LD_LIBRARY_PATH': '/app/.heroku/vendor/lib'... 
  'HOME': '/app', '_': '/app/.heroku/python/bin/python', 
  'PATH': '/app/.heroku/python/bin:/usr/local/bin:/usr/bin:/bin'...
}

(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ heroku config
=== damp-dusk-5382 Config Vars
DATABASE_URL: postgres://dbuser:[email protected]:5432/dbname
HEROKU_POSTGRESQL_ORANGE_URL: postgres://dbuser:[email protected]:5432/dbname

Исследовать:

Сохранить конфигурацию в среде: из приложения «Двенадцать факторов».

@adamwiggins написал:

Двенадцатифакторное приложение хранит конфигурацию в переменных среды ... Переменные окружения легко менять между развертываниями без изменения кода; в отличие от файлов конфигурации.

dj_database_url.config() возвращает пустой объект: с форумов Heroku

@chrisantonick ответил:

... dj_database_url.config () получает учетные данные Postgres из переменных среды Heroku. Но на вашем локальном компьютере этих переменных нет. Вы должны поместить их в свой сценарий оболочки / venv / bin / activate ... поместите туда переменные. что-то вроде
DATABASE_URL = "xxx"
экспорт DATABASE_URL
Для каждой нужной вещи. Затем ... "деактивировать" ... и ... "активировать" снова, чтобы перезапустить его.

При запуске инструкций Django и Heroku возникла ошибка "Неправильная настройка": на форумах Heroku

@jwpe ответил:

... dj-database-url - отличная утилита, поскольку она позволяет вам использовать точно такой же код settings.py в ваших средах разработки и производства, как рекомендовано в «12-факторных принципах приложения» ... what dj_database_url.config () ищет переменную среды DATABASE_URL, а затем анализирует ее в предпочтительном формате Django ... если вы вручную не создали и не продвинули базу данных postgres на Heroku, DATABASE_URL не будет присутствовать, и возникнет ошибка ImproperlyConfigured . Установка значения по умолчанию для dj_database_url.config () в качестве URL-адреса вашей локальной БД - это один из способов убедиться, что ваше приложение будет работать в среде разработки. Однако это не обязательно единственный способ. Возможно, лучшая альтернатива - вручную установить DATABASE_URL в локальном файле .env. Затем при локальном запуске приложения с помощью Foreman оно будет загружено как переменная среды, и dj_database_url найдет ее. Таким образом, ваш .env будет содержать:

DATABASE_URL=postgres://user:pass@localhost/dbname

Это означает, что в settings.py вам потребуется только:

DATABASES['default']= dj_database_url.config()

... Преимущество использования локальной переменной среды вместо одной жестко запрограммированной по умолчанию состоит в том, что ваш код будет работать в любой среде, где установлен DATABASE_URL. Если вы измените имя своей локальной БД или хотите запустить код на другом компьютере разработчика, вам нужно только обновить файл .env вместо того, чтобы возиться с settings.py.

Как управлять настройками Django для производства / подготовки / разработки? с форумов Heroku

@rdegges ответил:

... пытаясь заставить ваше приложение вести себя таким образом, чтобы:

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

Лучший способ добиться этого - использовать переменные среды!… Переменные среды - самый элегантный (и масштабируемый) способ управления конфигурацией приложения между различными средами… Вместо того, чтобы иметь много файлов настроек, определите один файл: settings.py и он использует переменные среды для получения служебной информации и учетных данных ... На Heroku вы можете установить переменные среды вручную, запустив:

$ heroku config:set SOME_VARIABLE=some_value

... всегда есть отличный инструмент Кеннета Рейца для автообъявлений. Это позволяет вам определить простой файл .env в каталоге вашего проекта ... И каждый раз, когда вы входите в каталог проекта, эти переменные среды будут автоматически устанавливаться, так что вам не придется делать ничего особенного! Просто запустите свой проект и все заработает как положено: python manage.py runserver

В качестве первой попытки:

Я вручную установил DATABASE_URL в моем файле .env: DATABASE_URL=postgres://dbuser:[email protected]:5432/dbname

Но когда я запускаю команду $ foreman start:

(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman start
17:25:39 web.1  | started with pid 319
17:25:39 web.1  | 2013-09-11 17:25:39 [319] [INFO] Starting gunicorn 18.0
17:25:39 web.1  | 2013-09-11 17:25:39 [319] [INFO] Listening at: http://0.0.0.0:5000 (319)
17:25:39 web.1  | 2013-09-11 17:25:39 [319] [INFO] Using worker: sync
17:25:39 web.1  | 2013-09-11 17:25:39 [322] [INFO] Booting worker with pid: 322

и попытался открыть свое приложение в браузере http://0.0.0.0:5000:

17:26:59 web.1  | 2013-09-11 10:26:59 [322] [ERROR] Error handling request
17:26:59 web.1  | Traceback (most recent call last):
17:26:59 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 131, in handle_request
17:26:59 web.1  |     respiter = self.wsgi(environ, resp.start_response)
17:26:59 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/dj_static.py", line 59, in __call__
17:26:59 web.1  |     return self.application(environ, start_response)
17:26:59 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 236, in __call__
17:26:59 web.1  |     self.load_middleware()
17:26:59 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 53, in load_middleware
17:26:59 web.1  |     raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
17:26:59 web.1  | ImproperlyConfigured: Error importing middleware django.contrib.auth.middleware: "dlopen(/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so, 2): Library not loaded: @loader_path/../lib/libssl.1.0.0.dylib
17:26:59 web.1  |   Referenced from: /Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so
17:26:59 web.1  |   Reason: image not found"

Однако dj_database_url.config() вернул:

{
  'ENGINE': 'django.db.backends.postgresql_psycopg2', 
  'NAME': 'dbname', 
  'HOST': 'ec2-23-21-196-147.compute-1.amazonaws.com', 
  'USER': 'dbuser', 
  'PASSWORD': 'dbpassword', 
  'PORT': 5432
}

В качестве второй попытки:

Я вручную установил DATABASE_URL в моем файле .env, изменив хост. Я заменил ec2-184-73-162-34.compute-1.amazonaws.com:5432 на localhost: 5000. $ deactivate, а затем снова $ workon hellodjango_venv.

DATABASE_URL=postgres://dbuser:dbpassword@localhost:5000/dbname

Но когда я запускаю команду $ foreman start:

(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman start
17:38:41 web.1  | started with pid 687
17:38:41 web.1  | 2013-09-11 17:38:41 [687] [INFO] Starting gunicorn 18.0
17:38:41 web.1  | 2013-09-11 17:38:41 [687] [INFO] Listening at: http://0.0.0.0:5000 (687)
17:38:41 web.1  | 2013-09-11 17:38:41 [687] [INFO] Using worker: sync
17:38:41 web.1  | 2013-09-11 17:38:41 [690] [INFO] Booting worker with pid: 690

и попытался открыть свое приложение в браузере http://0.0.0.0:5000:

17:38:46 web.1  | 2013-09-11 10:38:46 [690] [ERROR] Error handling request
17:38:46 web.1  | Traceback (most recent call last):
17:38:46 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 131, in handle_request
17:38:46 web.1  |     respiter = self.wsgi(environ, resp.start_response)
17:38:46 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/dj_static.py", line 59, in __call__
17:38:46 web.1  |     return self.application(environ, start_response)
17:38:46 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 236, in __call__
17:38:46 web.1  |     self.load_middleware()
17:38:46 web.1  |   File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 53, in load_middleware
17:38:46 web.1  |     raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
17:38:46 web.1  | ImproperlyConfigured: Error importing middleware django.contrib.auth.middleware: "dlopen(/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so, 2): Library not loaded: @loader_path/../lib/libssl.1.0.0.dylib
17:38:46 web.1  |   Referenced from: /Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so
17:38:46 web.1  |   Reason: image not found"

На этот раз dj_database_url.config() вернул:

{
  'ENGINE': 'django.db.backends.postgresql_psycopg2', 
  'NAME': 'dbname', 
  'HOST': 'localhost', 
  'USER': 'dbuser', 
  'PASSWORD': 'dbpassword', 
  'PORT': 5000
}

В качестве третьей попытки:

Я установил autoenv mac-pol:~ oubiga$ pip install autoenv
Из этой Поваренной книги Кеннет Райтц написал:

use_env() {
  typeset venv
  venv="$1"
  if [[ "${VIRTUAL_ENV:t}" != "$venv" ]]; then
    if workon | grep -q "$venv"; then
      workon "$venv"
    else
      echo -n "Create virtualenv $venv now? (Yn) "
      read answer
      if [[ "$answer" == "Y" ]]; then
        mkvirtualenv "$venv"
      fi
    fi
  fi
}

в моем файле .bashrc.

Я запускаю $ foreman start команду:

(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman start
18:11:57 web.1  | started with pid 1104
18:11:57 web.1  | 2013-09-11 18:11:57 [1104] [INFO] Starting gunicorn 18.0
18:11:57 web.1  | 2013-09-11 18:11:57 [1104] [INFO] Listening at: http://0.0.0.0:5000 (1104)
18:11:57 web.1  | 2013-09-11 18:11:57 [1104] [INFO] Using worker: sync
18:11:57 web.1  | 2013-09-11 18:11:57 [1107] [INFO] Booting worker with pid: 1107

и попытался открыть свое приложение в браузере http://0.0.0.0:5000: Сработало!

^CSIGINT received
18:12:06 system | sending SIGTERM to all processes
18:12:06 web.1  | 2013-09-11 11:12:06 [1107] [INFO] Worker exiting (pid: 1107)
SIGTERM received
18:12:06 web.1  | 2013-09-11 18:12:06 [1104] [INFO] Handling signal: int
18:12:06 web.1  | 2013-09-11 18:12:06 [1104] [INFO] Shutting down: Master
18:12:06 web.1  | exited with code 0

Но dj_database_url.config() снова возвращает пустой словарь.

В качестве последней попытки:

Мне была интересна команда python manage.py runserver, и я ее проверил.

(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman run python hellodjango/manage.py runserver
Validating models...

0 errors found
September 11, 2013 - 18:42:37
Django version 1.5.2, using settings 'hellodjango.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

и попытался открыть свое приложение в браузере http://127.0.0.1:8000/: Не сработало!

Был поднят ImportError: No module named hellodjango.urls.

Я заменил ROOT_URLCONF = 'hellodjango.hellodjango.urls' в моем файле settings.py на ROOT_URLCONF = 'hellodjango.urls', и, наконец, это сработало.

Как и ожидалось, dj_database_url.config() вернул пустой словарь.

So:

Теперь я немного ошеломлен. Боюсь, я неправильно понимаю здесь некую основную концепцию.

  • Какой смысл использовать Gunicorn вместо сервера разработки Django?
  • Почему dj_database_url.config() иногда возвращает полностью заполненный словарь, а иногда и пустой?
  • Могу ли я вручную установить переменные среды в файле .env? Нужно ли мне устанавливать такие инструменты, как autoenv, heroku-config ...?

Заранее спасибо.


person oubiga    schedule 12.09.2013    source источник
comment
Я чувствую вашу боль, как человек, решающий подобные проблемы с помощью моего первого приложения Django. У меня нет ответа, но удачи.   -  person Gowiem    schedule 25.09.2013
comment
@ Gowie47, спасибо. В IRC мне сказали, что Postgres.app имеет к нему отношение. Форумы Heroku.   -  person oubiga    schedule 26.09.2013
comment
Хм .. Я тоже использую Postgres.app локально. Я только что понял, что для моего метода .config () у меня есть следующее: dj_database_url.config(default='postgres://localhost/hocg') Это то, что вам в итоге пришлось сделать? Создать базу данных через postgres, а затем дать ей URL-адрес localhost / name?   -  person Gowiem    schedule 26.09.2013
comment
import dj_database_url DATABASES['default'] = dj_database_url.config() в settings.py достаточно. Вы можете проверить репозиторий dj-database-url и этот вопрос на форумах Heroku для получения более подробной информации.   -  person oubiga    schedule 29.09.2013


Ответы (1)


Я тоже застрял с postgres, вот что я сделал в settings.py, чтобы добавить локальные настройки:

DATABASES = {
'default': dj_database_url.config(default='postgres://<user>:<password>@<host>/<dbname>')
}

Конечно, вы должны создать базу данных, выполнив шаги postgres. Решение было из https://discussion.heroku.com/t/dj-database-url-config-is-returning-an-empty-object/55/9

person Song Keang    schedule 20.11.2013