我的目标:
我打算按照“十二要素应用程序”方法在 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
我安装了 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
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())
这就是我的 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: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
研究:
在环境中存储配置:来自 The Twelve-Factor App
@adamwiggins 写道:
十二因素应用程序将配置存储在环境变量中......环境变量很容易在部署之间更改,而无需更改任何代码;不像配置文件。
dj_database_url.config()
正在返回一个空对象:来自 Heroku 论坛
@chrisantonick 回复:
... dj_database_url.config() 从 Heroku 环境变量中获取 Postgres 凭据。但是,在您的本地机器上,这些变量不存在。你必须把它们放在你的 /venv/bin/activate shell 脚本中……把变量放在那里。像
DATABASE_URL = "xxx"
export DATABASE_URL
对于它需要的每一件事。然后...“停用”...并再次...“激活”以重新启动它。
Django 和 Heroku 入门指令引发了错误配置错误:来自 Heroku 论坛
@jwpe 回复:
... dj-database-url 是一个很棒的实用程序,因为它允许您在开发和生产环境中使用完全相同的 settings.py 代码,正如“12 因素应用程序原则”中所推荐的那样...什么 dj_database_url.config () 正在寻找 DATABASE_URL 环境变量,然后将其解析为 Django 的首选格式...如果您尚未在 Heroku 上手动创建和提升 postgres 数据库,则 DATABASE_URL 将不存在,并且将引发 ImproperlyConfigured 错误. 将 dj_database_url.config() 的默认值设置为本地 DB 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。
如何管理生产/登台/开发 Django 设置?:来自 Heroku 论坛
@rdegges 回复:
...试图让您的应用程序以如下方式运行:
- 当您在笔记本电脑上运行该应用程序时,它使用您的本地 Postgres 服务器。
- 当您在暂存 Heroku 应用程序上运行该应用程序时,它使用 Postgres 服务器插件。
- 当您在生产 Heroku 应用程序上运行该应用程序时,它使用 Postgres 服务器插件。
实现这一点的最佳方法是使用环境变量!...环境变量是处理不同环境之间的应用程序配置的最优雅(和可扩展)的方式...与其拥有许多设置文件,不如定义一个文件:settings.py,并拥有它利用环境变量来提取服务信息和凭据...在 Heroku 上,您可以通过运行手动设置环境变量:
$ heroku config:set SOME_VARIABLE=some_value
... 总是有 Kenneth Reitz 伟大的 autoenv 工具。这使您可以在项目目录中定义一个简单的 .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
并试图在浏览器中打开我的应用程序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 文件中手动设置更改主机。我用“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
并试图在浏览器中打开我的应用程序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
}
作为第三次尝试:
我安装了 autoenvmac-pol:~ oubiga$ pip install autoenv
从这本Cookbook 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
}
在我的 .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()
返回了一个空字典。
所以:
现在,我感到有些不知所措。恐怕我在这里误解了一些核心概念。
- 使用 gunicorn 而不是 Django 开发服务器有什么意义?
- 为什么
dj_database_url.config()
有时返回一个完全填充的字典,有时返回一个空字典? - 我可以在 .env 文件中手动设置环境变量吗?我需要安装 autoenv、heroku-config 等工具吗?
先感谢您。