Django:開発と本番の設定を管理する方法は?


128

基本的なアプリを開発しています。展開段階で、ローカル設定と運用設定の両方が必要であることが明らかになりました。

次のことを知っておくと便利です。

  • 開発および本番環境での対処方法。
  • django-debug-toolbarなどのアプリを開発環境でのみ維持する方法。
  • 開発と配置の設定に関するその他のヒントとベストプラクティス。

回答:


108

DJANGO_SETTINGS_MODULE環境変数の設定は、Djangoにファイルのコントロールがロードされます。

したがって、それぞれの環境に個別の構成ファイルを作成し(もちろんimport *、別々の「共有設定」ファイルから両方を構成できることに注意してください)、を使用DJANGO_SETTINGS_MODULEして、どちらを使用するかを制御します。

方法は次のとおりです。

Djangoのドキュメントに記載されているように:

DJANGO_SETTINGS_MODULEの値は、mysite.settingsなどのPythonパス構文である必要があります。設定モジュールはPythonインポート検索パス上にある必要があることに注意してください。

それで、あなたが作成し、ソースリポジトリにあるmyapp/production_settings.pymyapp/test_settings.pyしましょう。

その場合、DJANGO_SETTINGS_MODULE=myapp.production_settings前者を使用するように設定しDJANGO_SETTINGS_MODULE=myapp.test_settings、後者を使用するように設定します。


これ以降、問題はDJANGO_SETTINGS_MODULE環境変数の設定に要約されます。

DJANGO_SETTINGS_MODULEスクリプトまたはシェルを使用した設定

次に、ブートストラップスクリプトまたはプロセスマネージャーを使用して(環境を設定することにより)正しい設定をロードするか、Djangoを起動する前にシェルから実行しますexport DJANGO_SETTINGS_MODULE=myapp.production_settings

このエクスポートはシェルからいつでも実行できることに注意してください—自分.bashrcや他の人に住んでいる必要はありません。

DJANGO_SETTINGS_MODULEプロセスマネージャーを使用した設定

環境を設定するブートストラップスクリプトを書くのが好きでない場合(そして、そのように感じる非常に十分な理由がある場合)、プロセスマネージャーを使用することをお勧めします。


最後に、変数を利用して設定を完全に異なる場所に保存できることに注意してくださいPYTHONPATH(たとえば、運用サーバー上の設定をに保存します/etc/)。これにより、構成をアプリケーションファイルから分離できます。それが必要かどうかは、アプリの構造によって異なります。


7
明確にするために、settings.pyファイルはSiteName/settings.pyデフォルトで格納されているため、代替設定ファイルを同じディレクトリに配置したDJANGO_SETTINGS_MODULE="SiteName.test_settings"場合、bin / activateに追加された行はそうでなければなりません。
alexbhandari 2014年

2
偶然にも、この手順を順を追って行う方法についてのチュートリアルを知っていますか。私はDjangoを初めて使用し、DJANGO_SETTINGS_MODULEまたはPYTHONPATHを設定する場所がわかりません
イエスアルマラル-Hackaprende

このソリューションは、conda envには当てはまらないようです。conda envにはbin / activateはありません。
Pouya Yousefi

1
@PouyaYousefi:この答えを使用するためにvirtualenvを使用する必要はまったくありません。答えは、実際には2つのステップに要約されます。a)個別の設定ファイルを使用DJANGO_SETTINGS_MODULEし、b)使用するものを選択するために使用します。変更bin/activate は後者を行うためのものです(TBH、これはとにかくこれは良いアイデアではないと思うので、それを削除しました)が、それだけではありません。
Thomas Orozco

pycharmコミュニティエディションでDjangoを使用していて、コマンドラインとpycharmコミュニティの両方で単体テストを正しく実行する必要がある場合にも役立ちます。ソースリポジトリのmyapp / settings.pyに単純な設定ファイルを1つだけ作成したとします。その場合、メニューRUN / Edit Configuration / Environment変数で「DJANGO_SETTINGS_MODULE = myapp.settings」を設定して、後者を使用してテストケースを実行します。
F.Tamy

57

デフォルトではプロダクション設定を使用しますが、ファイルとsettings_dev.py同じフォルダーにというファイルを作成しsettings.pyます。のようなオーバーライドをそこに追加しますDEBUG=True

開発に使用するコンピューターで、これを~/.bashrcファイルに追加します。

export DJANGO_DEVELOPMENT=true

settings.pyファイルの下部に、以下を追加します。

# Override production variables if DJANGO_DEVELOPMENT env variable is set
if os.environ.get('DJANGO_DEVELOPMENT'):
    from settings_dev import *  # or specific overrides

*Pythonでは一般的にインポートを避ける必要があります)

デフォルトでは、運用サーバーは何も上書きしません。できた!

他の回答と比較して、これは更新PYTHONPATHや、DJANGO_SETTINGS_MODULE一度に1つのdjangoプロジェクトでのみ作業できる設定を必要としないため、よりシンプルです。


8
これは正解ではないのですか?SOは、今日、本当に混乱しています。Ty cs01
codyc4321

if os.environ.get('DJANGO_DEVELOPMENT', 'true')も動作します。上記のis not true方法でPython 3.6にインポートできなかったため、これについてのみ言及します。
brt

1
@brtこれは悪い考えですDEV。パブリックサーバー上のプライベートデータをリークする設定を常に使用します。DJANGO_DEVELOPMENT環境変数が存在することを確認したいだけです(つまりis not None)。
cs01 2017年

情報をありがとう、@ cs01。間違った設定の読み込みでサイトを爆破したときに何か問題があったことに気付きsettings_dev.pyましたが、サーバーに読み込まれている理由がわかりませんでした。
brt 2017年

2
@ cs01 is not Noneチェックを外すだけで、それが存在し、真実であることを確認するまで、私は行きます。またos.getenv、略記
Tjorriemorrie、

35

通常、環境ごとに1つの設定ファイルと共有設定ファイルがあります。

/myproject/
  settings.production.py
  settings.development.py
  shared_settings.py

私の環境ファイルのそれぞれは:

try:
    from shared_settings import *
except ImportError:
    pass

これにより、必要に応じて共有設定をオーバーライドできます(そのスタンザの下に変更を追加することにより)。

次に、settings.pyにリンクして、使用する設定ファイルを選択します。

ln -s settings.development.py settings.py

2
pep8の禁止にどのように対処しimport *ますか?そのチェックを無効にしますか?私は、このインポートを包みましたexec()が、その後、私は、このファイルで定義されていない変数に条件文を持つことができない、また私は変更することができINSTALLED_APPS、それが「未定義」ですので、変数
ミハイル

11
設定ファイルは、Pythonで表現された構成であるため実際にはコードではないため、リントしません。
Daniel Watkins

17

これは私が6つの簡単なステップでそれを行う方法です:

  1. プロジェクトディレクトリ内にフォルダを作成し、名前を付けsettingsます。

    プロジェクトの構造:

    myproject/
           myapp1/
           myapp2/              
           myproject/
                  settings/
    
  2. 内4つのpythonファイルを作成しsettings、ディレクトリ、すなわち__init__.pybase.pydev.pyおよびprod.py

    設定ファイル:

    settings/
         __init__.py
         base.py
         prod.py
         dev.py 
    
  3. 開い__init__.pyて、次のコンテンツを入力します。

    init .py:

    from .base import *
    # you need to set "myproject = 'prod'" as an environment variable
    # in your OS (on which your website is hosted)
    if os.environ['myproject'] == 'prod':
       from .prod import *
    else:
       from .dev import *
    
  4. 開いbase.pyて、すべての一般的な設定(本番と開発の両方で使用されます)を入力します。次に例を示します。

    base.py:

    import os
    ...
    INSTALLED_APPS = [...]
    MIDDLEWARE = [...]
    TEMPLATES = [{...}]
    ...
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    MEDIA_ROOT = os.path.join(BASE_DIR, '/path/')
    MEDIA_URL = '/path/'
    
  5. dev.pyたとえば、開発に固有のものを開いて含めます。

    dev.py:

    DEBUG = True
    ALLOWED_HOSTS = ['localhost']
    ...
    
  6. prod.pyたとえば、プロダクション固有のものを開いて含めます。

    prod.py:

    DEBUG = False
    ALLOWED_HOSTS = ['www.example.com']
    LOGGING = [...]
    ...
    

10

複数のsettings*.pyファイルを作成し、環境ごとに変更する必要がある変数を推定します。次に、マスターsettings.pyファイルの最後に次のように入力します。

try:
  from settings_dev import *
except ImportError:
  pass

settings_*ステージごとに個別のファイルを保持します。

settings_dev.pyファイルの一番上に、これを追加します:

import sys
globals().update(vars(sys.modules['settings']))

変更する必要がある変数をインポートするには

このwikiエントリには、設定を分割する方法に関するより多くのアイデアがあります。


バーハム、ありがとう!アプリをデプロイするときに、設定の動作を確認するには、settings_devファイルを削除する必要がありますか?
クリスチャンローバック

はい、またはインポートを次のものに置き換えますsettings_prod.py
Burhan Khalid

1
デプロイでマスターのsettings.pyファイルを編集することは、バージョン管理と衝突することを意味します。そのため、これが必ずしも最善の方法であるとは限りません。Thomas Orozcoのオプションが最善だと思います。DJANGO_SETTINGS_MODULEは、virtualenv postactivateスクリプト、またはgunicornまたはmod_wsgiのセットアップで設定できます
Steve Jalim

1
おそらく、ステージ固有のファイルをソース管理に追加しないでください。プロジェクトのステージに固有の設定をプッシュしないことが理解されたと思います。
Burhan Khalid

virtualenvを使用している場合、通常はデフォルトで{{project_name}}。settingsになります。したがって、「設定」はsys.modulesのキーにはなりません。'myproject.settings'(またはプロジェクト名が何であれ)になります。を使用modname = "%s.settings" % ".".join(__name__.split('.')[:-1])して完全なモジュール名を取得してから、を取得できますglobals().update(vars(sys.modules[modname]))。私にはそれがうまく機能していることがわかります。もちろん、プログラムで文字列を優先してモジュール名を決定することについて少し説明しなくても、ほとんどの場合はおそらく機能します。
エリック

9

私は素晴らしいdjango-configurationsを使用し、すべての設定はmyに保存されていsettings.pyます:

from configurations import Configuration

class Base(Configuration):
    # all the base settings here...
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    ...

class Develop(Base):
    # development settings here...
    DEBUG = True 
    ...

class Production(Base):
    # production settings here...
    DEBUG = False

Djangoプロジェクトを構成するために、私はただドキュメントに従ってきました。


7

使用するアプローチは次のとおりです。

  • settings読みやすくするために設定を複数のファイルに分割するモジュール。
  • .env.jsongitリポジトリから除外したい、または環境固有の資格情報とパラメーターを保存するファイル。
  • env.py読み込むファイル.env.jsonのファイルを

次の構造を考えます:

...
.env.json           # the file containing all specific credentials and parameters
.gitignore          # the .gitignore file to exclude `.env.json`
project_name/       # project dir (the one which django-admin.py creates)
  accounts/         # project's apps
    __init__.py
    ...
  ...
  env.py            # the file to load credentials
  settings/
    __init__.py     # main settings file
    database.py     # database conf
    storage.py      # storage conf
    ...
venv                # virtualenv
...

.env.jsonように:

{
    "debug": false,
    "allowed_hosts": ["mydomain.com"],
    "django_secret_key": "my_very_long_secret_key",
    "db_password": "my_db_password",
    "db_name": "my_db_name",
    "db_user": "my_db_user",
    "db_host": "my_db_host",
}

そしてproject_name/env.py

<!-- language: lang-python -->
import json
import os


def get_credentials():
    env_file_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    with open(os.path.join(env_file_dir, '.env.json'), 'r') as f:
        creds = json.loads(f.read())
    return creds


credentials = get_credentials()

次の設定が可能です。

<!-- language: lang-py -->
# project_name/settings/__init__.py
from project_name.env import credentials
from project_name.settings.database import *
from project_name.settings.storage import *
...

SECRET_KEY = credentials.get('django_secret_key')

DEBUG = credentials.get('debug')

ALLOWED_HOSTS = credentials.get('allowed_hosts', [])

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    ...
]

if DEBUG:
    INSTALLED_APPS += ['debug_toolbar']

...

# project_name/settings/database.py
from project_name.env import credentials

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': credentials.get('db_name', ''),
        'USER': credentials.get('db_user', ''),
        'HOST': credentials.get('db_host', ''),
        'PASSWORD': credentials.get('db_password', ''),
        'PORT': '5432',
    }
}

このソリューションの利点は次のとおりです。

  • gitリポジトリを変更せずにローカル開発用のユーザー固有の認証情報と構成
  • 環境固有の構成、たとえば、3つの異なる環境を.env.jsondev、stagging、production などの3つの異なる環境に設定できます
  • 資格情報がリポジトリにありません

これがお役に立てば幸いです。この解決策に関する警告が表示された場合はお知らせください。


どこ仮定envと交換することでdevprodなど?古いsettings.pyファイルには何が入っていますか?何が入っstorage.pyているのdatabase.py
dbinott 2018年

こんにちは@dbinott、env.pyファイルを簡単に更新できるので、環境変数を使用して、ロードするファイルを選択できます
Charlesthk

例:conf = os.environ.get( 'CONF'、 '')file_ = f ".env。{conf} .json"
Charlesthk

ネイティブPythonデータ型ではなく、なぜjsonを使用するのですか?
空爆

4

以下のファイル構造を使用します。

project/
   ...
   settings/
   settings/common.py
   settings/local.py
   settings/prod.py
   settings/__init__.py -> local.py

したがって__init__.py、リンク(UNIXではlnまたはウィンドウではmklink)もリンクlocal.pyできるprod.pyので、project.settingsモジュール内の構成はクリーンで整理されており、特定の構成を使用DJANGO_SETTINGS_MODULEするproject.settings.prod場合は、必要に応じて環境変数を使用できます。本番環境用のコマンドを実行します。

ファイルprod.pylocal.py

from .shared import *

DATABASE = {
    ...
}

また、shared.pyファイルは特定の構成なしでグローバルとして保持されます。


3

cs01の答えを構築する:

環境変数に問題がある場合は、その値を文字列に設定します(例:)DJANGO_DEVELOPMENT="true"

また、cs01のファイルワークフローを次のように変更しました。

#settings.py
import os
if os.environ.get('DJANGO_DEVELOPMENT') is not None:
    from settings_dev import * 
else:
    from settings_production import *
#settings_dev.py
development settings go here
#settings_production.py
production settings go here

これにより、Djangoは適切な設定ファイルを実行する前に、設定ファイル全体を読み取る必要がなくなります。このソリューションは、本番サーバーにのみ存在するものが本番ファイルに必要な場合に便利です。

注:Pythonの3で、インポートしたファイルが持っている必要が.追加さ(例えばfrom .settings_dev import *


1

1つの設定ファイルを保持する必要があり、開発オペレーティングシステムが本番オペレーティングシステムと異なる場合は、これをsettings.pyの下部に配置できます。

from sys import platform
if platform == "linux" or platform == "linux2":
    # linux
    # some special setting here for when I'm on my prod server
elif platform == "darwin":
    # OS X
    # some special setting here for when I'm developing on my mac
elif platform == "win32":
    # Windows...
    # some special setting here for when I'm developing on my pc

続きを読む:Pythonでオペレーティングシステムを確認するにはどうすればよいですか?


1

これは回答されたようですが、バージョン管理と組み合わせて使用​​する方法は次のとおりです。

.gitignoreにも追加するローカル開発環境の設定と同じディレクトリにenv.pyファイルを設定します。

env.py:

#!usr/bin/python

DJANGO_ENV = True
ALLOWED_HOSTS = ['127.0.0.1', 'dev.mywebsite.com']

.gitignore:

mywebsite/env.py

settings.py:

if os.path.exists(os.getcwd() + '/env.py'):
    #env.py is excluded using the .gitignore file - when moving to production we can automatically set debug mode to off:
    from env import *
else:
    DJANGO_ENV = False

DEBUG = DJANGO_ENV

私はこれがうまく機能し、はるかにエレガントです-env.pyを使用すると、ローカル環境変数を簡単に確認でき、複数のsettings.pyファイルなどを使用せずにすべてを処理できます。このメソッドにより、実稼働サーバーで設定したくないあらゆる種類のローカル環境変数を使用できます。バージョン管理を介して.gitignoreを利用することで、すべてをシームレスに統合することもできます。


最も簡単なソリューション。ファイルConfig内のクラスですべてを定義することもできenv.pyます。次に、の代わりにimport *、モジュールをでインポートできますfrom env import Config。このようにos.path、このif チェックを使用すると、全体をはるかに簡単にすることができます。
Siddharthパンツ

0

settings.py生産に使用します。同じディレクトリsettings_dev.pyで上書き用に作成します。

# settings_dev.py

from .settings import * 

DEBUG = False

開発マシン上でDjangoアプリを実行します:

DJANGO_SETTINGS_MODULE=<your_app_name>.settings_dev python3 manage.py runserver

prodマシンでは、あたかもあるかのように実行し、settings.py他には何も実行しません。

利点

  1. settings.py (本番環境で使用)は、他の環境も存在するという事実に完全に依存しません。
  2. prodとdevの違いを確認するには、1つの場所を調べてくださいsettings_dev.py。コンフィギュレーションを収集する必要が散らばっていないsettings_prod.pysettings_dev.pysettings_shared.py
  3. プロダクションの問題のトラブルシューティング後に誰かがprod構成に設定を追加した場合、(明示的にオーバーライドされない限り)開発構成にも表示されるので安心できます。したがって、異なる構成ファイル間の相違が最小限に抑えられます。

0

ファイル設定の問題で、コピーすることにしました

Project
   |---__init__.py   [ write code to copy setting file from subdir to current dir]
   |---settings.py  (do not commit this file to git)
   |---setting1_dir
   |         |--  settings.py
   |---setting2_dir
   |         |--  settings.py

djangoを実行すると、__ init__pyが実行されます。この時点で、settings.py in setting1_dir交換されsettings.py in Projectます。

別の環境を選択する方法は?

  • __init__.py直接変更します。
  • 変更するbashファイルを作成します__init__.py
  • Linuxでenvを変更してから、__init__.pyこの変数を読み取らせます。

なぜこのように使用するのですか?

同じディレクトリにあるあまり多くのファイルが好きではないため、あまりにも多くのファイルは他のパートナーを混乱させ、IDEにはあまり適していません(IDEは使用するファイルを見つけることができません)。

これらの詳細をすべて表示したくない場合は、プロジェクトを2つの部分に分割できます。

  1. プロジェクトをセットアップするためだけに、Spring Initializrのような小さなツールを作成します(ファイルのコピーのように実行します)。
  2. あなたのプロジェクトコード

0

別のapp.yamlファイルを使用して、Google Cloud App Engineの環境間で構成を変更しています。

これを使用して、ターミナルコマンドでプロキシ接続を作成できます。

./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:1433

https://cloud.google.com/sql/docs/sqlserver/connect-admin-proxy#macos-64-bit

ファイル:app.yaml

# [START django_app]
service: development
runtime: python37

env_variables:
  DJANGO_DB_HOST: '/cloudsql/myproject:myregion:myinstance'
  DJANGO_DEBUG: True

handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
  static_dir: static/

# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto
# [END django_app]

-1

これは私の解決策であり、開発、テスト、製品の環境が異なります

import socket

[...]

DEV_PC = 'PC059'
host_name = socket.gethostname()

if host_name == DEV_PC:
   #do something
   pass
elif [...]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.