Django:如何管理开发和生产设置?

时间:2012-05-19 10:12:34

标签: python django

我一直在开发一个基本的应用程序。现在处于部署阶段,我很清楚我需要本地设置和生产设置。

了解以下内容会很棒:

  • 如何最好地处理开发和生产设置。
  • 如何仅在开发环境中保留django-debug-toolbar等应用程序。
  • 有关开发和部署设置的任何其他提示和最佳做法。

16 个答案:

答案 0 :(得分:87)

DJANGO_SETTINGS_MODULE environment variable控制Django将加载哪个设置文件。

因此,您可以为各自的环境创建单独的配置文件(请注意,它们当然可以来自单独的“共享设置”文件中的import *),并使用DJANGO_SETTINGS_MODULE来控制使用哪个环境

以下是:

如Django文档中所述:

  

DJANGO_SETTINGS_MODULE的值应采用Python路径语法,例如: mysite.settings。请注意,设置模块应位于Python导入搜索路径上。

因此,我们假设您在源存储库中创建了myapp/production_settings.pymyapp/test_settings.py

在这种情况下,您分别设置DJANGO_SETTINGS_MODULE=myapp.production_settings使用前者,DJANGO_SETTINGS_MODULE=myapp.test_settings使用后者。


从现在开始,问题归结为设置DJANGO_SETTINGS_MODULE环境变量。

使用脚本或shell

设置DJANGO_SETTINGS_MODULE

然后,您可以使用引导脚本或进程管理器加载正确的设置(通过设置环境),或者在启动Django之前从shell运行它:export DJANGO_SETTINGS_MODULE=myapp.production_settings

请注意,您可以随时从shell运行此导出 - 它不需要存在于您的.bashrc或其他任何内容中。

使用流程管理器设置DJANGO_SETTINGS_MODULE

如果您不喜欢编写设置环境的引导脚本(并且有很好的理由感受到这种方式!),我建议使用进程管理器:


最后,请注意您可以利用PYTHONPATH变量将设置存储在完全不同的位置(例如,在生产服务器上,将它们存储在/etc/中)。这允许将配置与应用程序文件分开。您可能有也可能不想要,这取决于您的应用程序的结构。

答案 1 :(得分:33)

默认使用生产设置,但在与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') is not None:
    from settings_dev import * 

(请注意,在Python中通常应避免导入*,但这是一种独特的情况)

默认情况下,生产服务器不会覆盖任何内容。完成!

与其他答案相比,这个答案更简单,因为它不需要更新PYTHONPATH,或设置DJANGO_SETTINGS_MODULE,它只允许您一次处理一个django项目。

答案 2 :(得分:30)

我通常每个环境都有一个设置文件和一个共享设置文件:

/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

答案 3 :(得分:9)

创建多个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 entry有关于如何拆分设置的更多想法。

答案 4 :(得分:5)

这是我通过6个简单步骤完成的操作:

  1. 在项目目录中创建一个文件夹,并将其命名为settings

    项目结构:

    myproject/
           myapp1/
           myapp2/              
           myproject/
                  settings/
    
  2. settings目录内创建四个python文件,分别为init.pybase.pydev.pyprod.py

    设置文件:

    setting/
         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 = [...]
    ...
    

答案 5 :(得分:4)

我使用了真棒django-configurations,所有设置都存储在我的import java.awt.BorderLayout; import java.awt.Container; import java.awt.GridLayout; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.Border; import javax.swing.JTextField; import javax.swing.JLabel; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import javax.swing.JList; public class GuiApp1 { public static void main(String args[]) { String title = (args.length == 0 ? "CheckBox Sample" : args[0]); JFrame frame = new JFrame(title); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final JPanel panel = new JPanel(new GridLayout(0, 1)); Border border = BorderFactory.createTitledBorder("Pizza Toppings"); panel.setBorder(border); JLabel label1 = new JLabel("Enter name below:"); panel.add(label1); JTextField field = new JTextField(20); panel.add(field); JCheckBox check = new JCheckBox("Car0"); panel.add(check); check = new JCheckBox("Car1"); panel.add(check); check = new JCheckBox("Car2"); panel.add(check); check = new JCheckBox("Car3"); panel.add(check); check = new JCheckBox("Car4"); panel.add(check); JButton button = new JButton("Submit"); final JPanel listPanel = new JPanel(); listPanel.setVisible(false); JLabel listLbl = new JLabel("Vegetables:"); listPanel.add(listLbl); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { listPanel.setVisible(!listPanel.isVisible()); panel.setVisible(!panel.isVisible()); } }); Container contentPane = frame.getContentPane(); contentPane.add(panel, BorderLayout.CENTER); contentPane.add(button, BorderLayout.SOUTH); frame.setSize(300, 300); frame.setResizable(true); frame.setVisible(true); frame.setLocationRelativeTo(null); } } 中:

settings.py

要配置Django项目,我只需遵循docs

答案 6 :(得分:3)

以下是我们使用的方法:

  • 一个settings模块,用于将设置拆分为多个文件以便于阅读;
  • 一个.env.json文件,用于存储我们希望从我们的git存储库中排除的凭据和参数,或者是特定于环境的文件;
  • 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存储库即可进行本地开发;
  • 特定于环境的配置,您可以拥有三个不同的环境,其中包含三个不同的.env.json,例如开发,停滞和生产;
  • 凭据不在存储库中

我希望这会有所帮助,如果您对此解决方案有任何警告,请告诉我。

答案 7 :(得分:2)

建立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 *

答案 8 :(得分:2)

我使用了文件结构:

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

因此__init__.pylocal.py中的链接(在unix或mklink中为ln)或prod.py,因此配置仍在project.settings模块中如果您想使用特定配置,则可以使用环境变量DJANGO_SETTINGS_MODULEproject.settings.prod,如果您需要为生产环境运行命令。

文件prod.pylocal.py

from .shared import *

DATABASE = {
    ...
}

并且shared.py文件在没有特定配置的情况下保持全局。

答案 9 :(得分:0)

如果要保留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

了解详情:How do I check the operating system in Python?

答案 10 :(得分:0)

这似乎已经得到解答,但是我使用的方法与版本控制相结合如下:

将env.py文件设置在与我也添加到.gitignore的本地开发环境中的设置相同的目录中:

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,我们也可以保持所有内容的无缝集成。

答案 11 :(得分: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

在生产机器上运行,就好像您只有settings.py而已。

优势

  1. settings.py(用于生产)完全不知道存在任何其他环境。
  2. 要查看prod和dev之间的区别,您只需查看一个位置-settings_dev.py。无需收集散布在settings_prod.pysettings_dev.pysettings_shared.py上的配置。
  3. 如果在解决生产问题后有人将设置添加到您的产品配置中,您可以放心,该设置也会出现在您的开发配置中(除非被显式覆盖)。因此,不同配置文件之间的差异将被最小化。

答案 12 :(得分: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无法找到我们使用的文件)

如果您不想看到所有这些详细信息,可以将项目分为两部分。

  1. 制作像Spring Initializr这样的小工具,仅用于设置您的项目。(类似于复制文件)
  2. 您的项目代码

答案 13 :(得分: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]

答案 14 :(得分:0)

我在生产的工作目录中创建了一个名为“production”的文件。

#settings.py
production = Path("production")
DEBUG = False

#if it's dev mode
if not production.is_file():
    INSTALLED_APPS +=[
       #apps_in_development_mode,
       #...
    ]
    DEBUG = True
    #other settings to override the default production settings

答案 15 :(得分:-1)

这是我的解决方案,包括dev,test和prod

的不同环境
import socket

[...]

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

if host_name == DEV_PC:
   #do something
   pass
elif [...]