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

Posted

技术标签:

【中文标题】在 Heroku 上部署 Django 应用程序:我可以在 .env 文件中手动设置环境变量吗?我需要安装 autoenv、heroku-config 等工具吗?【英文标题】:Deploying Django app on Heroku: Can I manually set environment variables in the .env file? Do I need to install tools like autoenv, heroku-config...? 【发布时间】:2013-09-16 04:34:45 【问题描述】:

我的目标:

我打算按照“十二要素应用程序”的方法在 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 点==1.4.1 虚拟环境==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-静态==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: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 写道:

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

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

@chrisantonick 回复:

... dj_database_url.config() 从 Heroku 环境变量。 但是,在您的本地计算机上,那些 变量不存在。你必须把它们放在你的 /venv/bin/activate shell script...把变量放在那里。 类似于 DATABASE_URL = "xxx" 导出 DATABASE_URL 对于它需要的每一件事。然后......“停用”......和......“激活” 再次重新启动它。

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

@jwpe 回复:

... dj-database-url 是一个很棒的实用程序,因为它允许您使用 开发和生产中完全相同的 settings.py 代码 环境,如“12 因素应用程序原则”中所推荐的……什么 dj_database_url.config() 正在寻找 DATABASE_URL 环境变量,然后解析成Django的preferred 格式...如果您还没有手动创建和提升 postgres 数据库 在 Heroku 上,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

如何管理生产/登台/开发 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

作为第一次尝试:

我在我的 .env 文件中手动设置了DATABASE_URLDATABASE_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

作为第二次尝试:

我在更改主机的 .env 文件中手动设置 DATABASE_URL。我用“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

作为第三次尝试:

我安装了 autoenv mac-pol:~ oubiga$ pip install autoenv 从CookbookKenneth 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() 再次返回一个空字典。

作为最后的尝试:

我对@9​​87654366@ 命令很好奇,并查看了它。

(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

我将 settings.py 文件中的 ROOT_URLCONF = 'hellodjango.hellodjango.urls' 替换为 ROOT_URLCONF = 'hellodjango.urls',它终于奏效了。

正如预期的那样,dj_database_url.config() 返回了一个空字典。

所以:

现在,我感到有些不知所措。恐怕我在这里误解了一些核心概念。

使用 gunicorn 代替 Django 开发服务器有什么意义? 为什么dj_database_url.config() 有时会返回填满的字典,有时返回空字典? 能否在 .env 文件中手动设置环境变量?是否需要安装 autoenv、heroku-config...等工具?

提前谢谢你。

【问题讨论】:

作为在我的第一个 Django 应用程序中处理这些类型问题的其他人,我感受到了你的痛苦。我没有给你答案,但祝你好运。 @Gowie47 谢谢。在 IRC 上有人说 Postgres.app 与它有关。 Heroku Forums. 嗯.. 我也在本地使用 Postgres.app。我刚刚意识到我的 .config() 方法有以下内容:dj_database_url.config(default='postgres://localhost/hocg') 这就是你最终不得不做的吗?通过 postgres 创建数据库,然后给它一个 localhost/name url? import dj_database_url DATABASES['default'] = dj_database_url.config() 在 settings.py 中就足够了。您可以查看dj-database-url repository 和this question on Heroku forums 了解更多详情。 【参考方案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

【讨论】:

以上是关于在 Heroku 上部署 Django 应用程序:我可以在 .env 文件中手动设置环境变量吗?我需要安装 autoenv、heroku-config 等工具吗?的主要内容,如果未能解决你的问题,请参考以下文章

在heroku上部署django网站时出错

找不到静态文件 - 在 Heroku 上部署 Django

Django:使用 sqlite3 作为数据库在 Heroku 上部署应用程序

在 Heroku 上部署 Django API + React 应用程序

在 Heroku 上部署现有的 Django 应用程序

在Heroku上部署Django应用程序:错误[R10]