关于python:Django本地设置

Django Local Settings

我试着在Django1.2中使用本地的_设置,但它对我不起作用。目前,我只是在我的项目中添加本地的u settings.py。

设置Py

1
2
3
4
5
6
7
8
9
10
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco1',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

本地设置.py

1
2
3
4
5
6
7
8
9
10
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco2',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

问题是local_settings.py不会覆盖settings.py。怎么了?


不能只添加local_settings.py,必须明确导入它。

在settings.py的最后,添加以下内容:

1
2
3
4
try:
    from local_settings import *
except ImportError:
    pass

这里有try/except块,这样当您还没有真正定义本地的_设置文件时,python就会忽略这个情况。


我认为这是最佳实践:

  • local_settingssettings进口
  • local_settings覆盖特定于本地环境的设置,特别是DATABASESSECRET_KEYALLOWED_HOSTSDEBUG变量。
  • 交给Django管理层指挥旗--settings=local_settings

您可以这样实现local_settings

1
2
3
4
5
6
7
8
9
10
11
12
from settings import *

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco2',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

其他几个要点:

  • settings.py处于版本控制中,以供贡献者使用的方式编写。
  • local_settings.py(或更常见的prod_settings.py)不在版本控制中,通过指定--settings=prod_settings或类似的方式在生产中使用。

尽可能少地触摸Stock设置文件也可以更容易地升级Django版本。当您将django升级到下一个版本时,请查看库存settings.py和您的版本的差异,并根据所做的更改采取必要的措施。默认值的更改可能很重要,您越少接触原始settings.py文件,越容易识别上游更改。


既然这个话题经常出现,那么让我总结一下为什么您可能会考虑使用这种方法:

  • 哑设置文件非常快速且易于更改,特别是在生产环境中。不需要python:任何白痴都可以在一个只列出名称和值的文件中跳入并更改数据库密码;特别是与一个复杂的python设置文件相比,这个文件中充满了神秘而危险的bigcaps名称。

  • 应用程序settings应与应用程序code完全分开。您可以将config.ini放在存储库根目录之外,再也不用担心repo-pull会破坏您的设置,或者您的个人设置会污染repo,或者设置中的智能代码。py不要让它进入repo中,这对其他人都有利。

这不适用于小型项目,但对于大型项目,我得出的结论是,本地的"设置"策略并不能减少它;随着时间的推移,足够多的应用程序编程会变得难以处理;主要是随着设置变得派生和/或相互依赖。设置可以根据本地设置作出反应,这可以很好地解释,强制导入local_settings文件向settings.py的中间移动。我发现事情开始变得一团糟。

我目前的解决方案是使用一个config文件,我把它命名为"local.ini"。它只保存那些在部署的实例之间实际发生更改的值。没有代码:它们只是值和布尔值:

1
2
3
4
5
6
7
8
[global]
domain = 127.0.0.1:8000
database_host = 127.0.0.1
database_name = test_database
debug = Yes
google_analytics_id = UA-DEV-1
payments = testing
use_cdn = No

有了它,我可以像对待任何其他应用程序代码一样对待settings.py:调整它,签入它,然后部署它,而不必担心针对本地的设置python代码中隐藏的任何代码进行测试。我的settings.py没有种族条件,当以后的设置取决于本地设置时,会出现这种情况,我可以打开和关闭功能,编写易于遵循的线性代码。当我忘记添加一些新值时,不再匆忙地调整本地的_设置文件,也不再有daves_local_settings.pybobs_local_settings.py文件潜入存储库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from ConfigParser import RawConfigParser
parser = RawConfigParser()

APPLICATION_ROOT = path.abspath(path.dirname(__file__))
parser.readfp(open(path.join(APPLICATION_ROOT, 'local.ini')))

# simple variables
DATABASE_HOST = parser.get('global', 'database_host')
DATABASE_NAME = parser.get('global', 'database_name')

# interdependencies
from version import get_cdn_version
CDN = 'd99phdomw5k72k.cloudfront.net'
if parser.getboolean('global', 'use_cdn'):
    STATIC_URL = '/{}/static/{}/'.format(CDN, get_cdn_version())
else:
    STATIC_URL = '/static/'


# switches
payments = parser.get('global', 'payments')
if payments == 'testing':
    PAYMENT_GATEWAY_ENDPOINT = 'https://api.sandbox.gateway.com'
else:
    PAYMENT_GATEWAY_ENDPOINT = 'https://api.live.gateway.com'

如果你遇到一个bofh,就像我曾经遇到过的,他会特别激动,因为他能够将local.ini作为/etc/ourapp.ini插入/etc目录中,从而使应用程序目录本身保持纯粹的库导出。当然,你可以用一个本地的u settings.py来实现这一点,但他最不想做的事情就是处理Python代码。他可以处理的简单配置文件。


我保存了一份__local_settings.py的副本:

  • 版本控制中忽略了local_settings.py,而不是__local_settings.py
  • 更新README.md以通知团队如何设置:cp {__,}local_settings.py(为本地设置制作副本)

在过去

我曾经导入那些设置。

1
2
3
4
5
6
7
# settings.py
DATABASE = {...}

try:
    from .local_settings import *
except ImportError:
    pass

现在

我只是从local_settings.py导入设置本身。

用以下命令:python manage.py runserver --settings=.local_settings

1
2
3
4
# local_settings.py & __local_settings.py
from .settings import *

DATABASE = {...}

因为,我通常不直接与manage.py交互,因为一些参数对我来说是明确必要的(例如address:port)。因此,我把所有这些命令都交给了我的以东。

例如,这里是我的makefile:

1
2
3
4
5
6
7
8
9
run:
    python manage.py runserver 0.0.0.0:8000 --settings=<proj>.local_settings

sh:
    python manage.py shell_plus --settings=<proj>.local_settings

dep:
    npm install
    pip install -r requirements.txt

因此:

1
2
3
make dep
make sh
make run

结论

如果您没有使用Makefile作为您的工作流,那么您可以使用前面的方法,但是如果您使用makefile,那么我认为最好在makefile中更加明确。


在运行服务器之前

export DJANGO_SETTINGS_MODULE=your_app_name.local_settings
您的应用程序名称应替换为您的应用程序名称。别忘了做

1
from settings import *

在本地的u settings.py文件中


另一种方法是使用python-dotenv和环境变量为不同的环境定制设置。

沿着您的settings.py一侧创建.env文件:

1
2
3
# .env
SECRET_KEY=your-secret-key
DATABASE_PASSWORD=your-database-password

在您的settings.py中添加以下代码:

1
2
3
4
5
6
7
8
# settings.py
from dotenv import load_dotenv
load_dotenv()

# OR, explicitly providing path to '.env'
from pathlib import Path  # python 3.4+
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

此时,来自.env文件的解析键/值作为环境变量存在,可以通过os.getenv()方便地访问它们:

1
2
3
4
# settings.py
import os
SECRET_KEY = os.getenv('SECRET_KEY')
DATABASE_PASSWORD = os.getenv('DATABASE_PASSWORD')


将其添加到文件settings.py的末尾

1
2
3
4
try:
    from .local_settings import *
except ImportError:
    pass

并使用新设置创建文件local_settings.py,例如

1
2
3
4
5
6
7
8
9
10
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco2',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

我找到了类似的解决方案。这是我对这个案例的配置:

设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
DEBUG = False

try:
    from local_settings import *

except ImportError:
    pass

if DEBUG is False:
    ALLOWED_HOSTS = ['sth.com']
    DATABASES = {
        ....
    }

本地设置.py:

1
2
3
4
5
6
from settings import *
ALLOWED_HOSTS = ['*']
DEBUG = True
DATABASES = {
    ...
}