在Heroku上部署Django应用程序:我可以在.env文件中手动设置环境变量吗?我是否需要安装autoenv,heroku-config等工具?

oub*_*iga 9 django heroku environment-variables gunicorn 12factor

我的目标:

我打算遵循"The Twelve-Factor App"方法在Heroku上构建我的Django应用程序.

介绍:

我正在关注"Heroku上的Django入门"快速入门指南.目前我有以下目录结构:

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

我安装了django-toolbelt,创建了我的简单Django应用程序,在我的Procfile中启动了这个过程...一切似乎工作正常,但是当我为Heroku环境配置应用程序并添加时问题就开始了:

import dj_database_url
DATABASES['default'] =  dj_database_url.config()
Run Code Online (Sandbox Code Playgroud)

到我的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'
}
Run Code Online (Sandbox Code Playgroud)

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
static == 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())
Run Code Online (Sandbox Code Playgroud)

这是我在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)
Run Code Online (Sandbox Code Playgroud)

这就是我在Procfile中的内容:

web: gunicorn hellodjango.hellodjango.wsgi  
Run Code Online (Sandbox Code Playgroud)

环境变量:

(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'
}
Run Code Online (Sandbox Code Playgroud)

在Heroku上:

环境变量:

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

{
  'DATABASE_URL': 'postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname', 
  'HEROKU_POSTGRESQL_ORANGE_URL': 'postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com: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:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname
HEROKU_POSTGRESQL_ORANGE_URL: postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname
Run Code Online (Sandbox Code Playgroud)

研究:

在环境中存储配置:来自The Twelve-Factor App

@adamwiggins写道:

十二因素应用程序将配置存储在环境变量中 ... Env变量很容易在部署之间更改,而无需更改任何代码; 与配置文件不同.

dj_database_url.config()正在返回一个空对象:来自Heroku论坛

@chrisantonick回答说:

... dj_database_url.config()从Heroku环境变量中获取Postgres凭据.但是,在本地计算机上,那些变量不存在.你必须把它们放在/ venv/bin/activate shell脚本中......把变量放在那里.像
DATABASE_URL ="xxx" 这样的东西
导出DATABASE_URL
对于它需要的每一件事.然后......"停用"......再次......"激活"重新启动它.

Django和Heroku指令入门引发了ErrorperlyConfigured错误:来自Heroku论坛

@jwpe回复:

... dj-database-url是一个很棒的实用程序,因为它允许您在开发和生产环境中使用完全相同的settings.py代码,如"12因素应用程序原则"中所建议的...... dj_database_url.config ()正在寻找DATABASE_URL环境变量,然后将其解析为Django的首选格式...如果你没有在Heroku上手动创建和提升postgres数据库,DATABASE_URL将不存在,并且将引发ImproperlyConfigured错误.将dj_database_url.config()的缺省值设置为本地数据库URL是确保应用程序在开发环境中正常工作的一种方法.但是,它不一定是唯一的方法.也许更好的选择是在本地.env文件中手动设置DATABASE_URL.然后,当使用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进行修改.

如何管理生产/登台/ dev Django设置?:来自Heroku论坛

@rdegges回复:

...尝试让您的应用程序以这样的方式运行:

  • 当您在笔记本电脑上运行应用程序时,它会使用您当地的Postgres服务器.
  • 当您在暂存Heroku应用程序上运行应用程序时,它使用Postgres服务器插件.
  • 当您在生产Heroku应用程序上运行应用程序时,它使用Postgres服务器插件.

实现这一目标的最佳方法是使用环境变量!...环境变量是处理不同环境之间的应用程序配置的最优雅(和可扩展)方式...而不是拥有许多设置文件,定义一个文件:settings.py,并且它利用环境变量来提取服务信息和凭证......在Heroku上,您可以通过运行以下方式手动设置环境变量:

$ heroku config:set SOME_VARIABLE=some_value
Run Code Online (Sandbox Code Playgroud)

...肯尼斯·雷茨总是有着极好的自动工具.这允许您在项目目录中定义一个简单的.env文件...每次进入项目目录时,这些环境变量都将自动设置,这样您就不必做任何特别的事情!只需运行您的项目,一切都将按预期工作:python manage.py runserver

作为第一次尝试:

我手动设置DATABASE_URL我的.env文件: DATABASE_URL=postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com: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
Run Code Online (Sandbox Code Playgroud)

并试图在浏览器中打开我的应用程序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"
Run Code Online (Sandbox Code Playgroud)

但是,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
}
Run Code Online (Sandbox Code Playgroud)

作为第二次尝试:

DATABASE_URL在我的.env文件中手动设置更改主机.我用"localhost:5000"替换了"ec2-184-73-162-34.compute-1.amazonaws.com:5432".$ 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
Run Code Online (Sandbox Code Playgroud)

并试图在浏览器中打开我的应用程序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"
Run Code Online (Sandbox Code Playgroud)

这一次,dj_database_url.config()返回:

{
  'ENGINE': 'django.db.backends.postgresql_psycopg2', 
  'NAME': 'dbname', 
  'HOST': 'localhost', 
  'USER': 'dbuser', 
  'PASSWORD': 'dbpassword', 
  'PORT': 5000
}
Run Code Online (Sandbox Code Playgroud)

作为第三次尝试:

我安装了autoenv mac-pol:~ oubiga$ pip install autoenv
从这本食谱 Kenneth Reitz写道,我把:

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
}
Run Code Online (Sandbox Code Playgroud)

在我的.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
Run Code Online (Sandbox Code Playgroud)

并试图在浏览器中打开我的应用程序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
Run Code Online (Sandbox Code Playgroud)

但是,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.
Run Code Online (Sandbox Code Playgroud)

并尝试在浏览器中打开我的应用程序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()返回一个空字典.

所以:

现在,我觉得有点不知所措.我担心我在这里误解了一些核心概念.

  • 使用gunicorn而不是Django开发服务器有什么意义?
  • 为什么dj_database_url.config()有时会返回一个完全填充的字典,有时候是空字典?
  • 我可以在.env文件中手动设置环境变量吗?我是否需要安装autoenv,heroku-config等工具?

先感谢您.

Son*_*ang 1

我也被 postgres 困住了,这是我在 settings.py 中添加本地设置的操作:

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

当然,您必须按照 postgres 步骤创建数据库。解决方案来自https://discussion.heroku.com/t/dj-database-url-config-is-returning-an-empty-object/55/9