【问题标题】:Django Local SettingsDjango 本地设置
【发布时间】:2011-06-22 01:13:14
【问题描述】:

我正在尝试在 Django 1.2 中使用 local_setting,但它对我不起作用。目前我只是将 local_settings.py 添加到我的项目中。

settings.py

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.
    }
}

local_settings.py

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。 怎么了?

【问题讨论】:

  • 在我读到这个问题的那一刻,有三个非常不同且都很有趣的答案。我对丹尼尔的解决方案感到困惑。在我看来,没有万能的解决方案。 Daniel 的解决方案简单高效。 jano 的解决方案以某种方式更清洁,这种方式仅在已经清洁的环境中才有意义,而且成本很低。 John 的解决方案在某种程度上更重量级,但在最受限制的环境中也很有趣。总而言之,只需选择适合您用例的最简单的。

标签: python django settings


【解决方案1】:

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

try:
    from .local_settings import *
except ImportError:
    pass

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

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.
    }
}

【讨论】:

    【解决方案2】:

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

    在您的settings.py 旁边创建.env 文件:

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

    将以下代码添加到您的settings.py

    # 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() 方便地访问它们:

    # settings.py
    import os
    SECRET_KEY = os.getenv('SECRET_KEY')
    DATABASE_PASSWORD = os.getenv('DATABASE_PASSWORD')   
    

    【讨论】:

      【解决方案3】:

      在运行服务器之前做

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

      from settings import *
      

      在您的 local_settings.py 文件中

      【讨论】:

      • 您应该从该行中省略 .py,(并且不要忘记将 appname 替换为您的实际应用程序)
      【解决方案4】:

      我找到了类似的解决方案。这是我对这种情况的配置:

      settings.py:

      DEBUG = False
      
      try:
          from local_settings import *
      
      except ImportError:
          pass
      
      if DEBUG is False:
          ALLOWED_HOSTS = ['sth.com']
          DATABASES = {
              ....
          }
      

      local_settings.py:

      from settings import *
      ALLOWED_HOSTS = ['*']
      DEBUG = True
      DATABASES = {
          ...
      }
      

      【讨论】:

      • 我尝试了多种解决方案,这对我有用。通过在页面顶部而不是在其他帖子中推荐的底部导入 local_settings。
      【解决方案5】:

      我保留了一份__local_settings.py:

      • local_settings.py 在版本控制中被忽略,但不是 __local_settings.py
      • 更新 README.md 以告知团队如何设置:cp {__,}local_settings.py(为他们的 local_settings 制作副本)

      过去

      我曾经导入这些设置。

      # settings.py
      DATABASE = {...}
      
      try:
          from .local_settings import *
      except ImportError:
          pass
      

      现在

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

      然后使用以下命令:python manage.py runserver --settings=<proj>.local_settings

      # local_settings.py & __local_settings.py
      from .settings import *
      
      DATABASE = {...}
      

      因为,我通常不直接与manage.py 交互,因为某些参数对我来说是明确需要的(例如address:port)。因此,我将所有这些命令都放入了我的Makefile

      例如,这是我的 Makefile:

      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
      

      因此:

      make dep
      make sh 
      make run
      

      结论

      如果您使用Makefile 作为您的工作流程,那么您可以使用较早的方法,但如果您使用的是makefile,那么我认为最好在您的工作流程中更加明确生成文件。

      【讨论】:

      • Makefile 只是一个想法和意见。尝试使用早期的方法可能会更好
      【解决方案6】:

      这是我认为的最佳做法:

      • local_settingssettings 导入
      • local_settings 覆盖特定于本地环境的设置,尤其是 DATABASESSECRET_KEYALLOWED_HOSTSDEBUG 变量
      • 将标志--settings=local_settings传递给django管理命令

      你可以像这样实现local_settings

      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 或类似名称在生产中使用。

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

      【讨论】:

      • 我喜欢这种方法。在升级 django 版本时,尽可能少地触摸空白设置文件可以更轻松地正确配置新设置。
      • 这应该是已接受的答案,请阅读已接受答案中的 cmets,了解该答案存在问题的原因(“在每个位置运行的未版本化代码”)。
      • 我看不出这与接受的答案有何不同。这个 local_settings 也不应该被版本化。如果是这样,开发人员可能会意外更改生产机器上的 local_settings。
      • @azmeuk 上下文很重要。 import * 通常很糟糕,但当它是文件中唯一的导入时完全可以接受。它应该local_settings.py中的导入
      【解决方案7】:

      由于该主题经常出现,让我总结一下您可能要考虑这种方法的原因:

      • 愚蠢的设置文件非常快速且易于更改;特别是在生产环境中。不需要python:任何白痴都可以进入并更改仅列出名称和值的文件中的数据库密码;尤其是与充满神秘危险 BIGCAPS 名称的复杂 python 设置文件相比。

      • 应用程序settings 应与应用程序code 完全分离。您可以将 config.ini 放在存储库根目录之外,再也不用担心 repo pull 会破坏您的设置,或者您的个人设置污染 repo,或者您的 settings.py 中的巧妙代码不会使其进入 repo 以使其他人受益.

      这不适用于小型项目,但在大型项目中,我得出的结论是 local_settings 策略并不能解决问题;随着时间的推移,足够多的应用程序编程变得难以处理;主要是因为设置变得衍生和/或相互依赖。设置根据本地设置做出反应可能有很好的理由,这会强制 local_settings 文件的导入爬向settings.py 的中间。发生这种情况时,我发现事情开始变得一团糟。

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

      [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:对其进行调整、签入和部署,而不必担心针对可能潜伏在 local_settings python 代码中的任何代码进行测试。我的settings.py 没有在以后的设置依赖于本地设置时出现的竞争条件,并且我可以打开和关闭功能,编写易于遵循的线性代码。当我忘记添加一些新值时,不再匆忙调整 local_settings 文件,也不再有 daves_local_settings.pybobs_local_settings.py 文件潜入存储库。

      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 目录中作为/etc/ourapp.ini 并保持应用程序目录本身保持纯净而感到特别兴奋存储库导出。当然你可以用 local_settings.py 做到这一点,但他想做的最后一件事就是把 python 代码弄得一团糟。一个他可以处理的简单配置文件。

      【讨论】:

      • 是什么让您想要使用与常规 Python 文件不同的语法(并且需要解析器)?这就是我们命名空间的原因。
      • 因为regular Python file 将被执行,而配置文件是一个非常简单的哑设置集合;没有诱惑让它做“聪明”的事情,任何白痴(例如非 python 人,或 12 个月后的你自己)都可以弄清楚如何更新基本设置,而不必担心破坏一切。
      • 语法实际上是相同的。我想这是一个偏好问题。
      • 就像我说的,小项目几乎没有回报;但是一旦你的 settings.py 超过 50 行,或者import local_settings.py 不再位于最底部,你就会看到更多的价值。
      • 对我来说,最糟糕的是您需要为每个设置值编写代码。而且,如果您只是导入文件中的所有内容,则需要从 stings 中转换变量(如果它们是其他东西)。另外,我喜欢连接事物。我的配置中也有很多列表和字典。
      【解决方案8】:

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

      在你的settings.py的最后,添加这个:

      try:
          from local_settings import *
      except ImportError:
          pass
      

      try/except 块在那里,以便 Python 在您尚未实际定义 local_settings 文件时忽略这种情况。

      【讨论】:

      • 是的 grep -r "local_setting" django 几乎可以保证这不是“开箱即用”的行为
      • 这种方法意味着您在每个位置都运行未版本化的代码。这是一种反模式。
      • @pydanny 你有什么建议?
      • @pydanny - 该答案明确表示local_settings.py (or more commonly prod_settings.py) is NOT in version control, and used in production by specifying --settings=prod_settings or similar. 因此,似乎未版本化的代码仍在每个位置运行。不是这样吗?
      • 传递异常是一个非常糟糕的主意。如果 local_settings.py 只是有语法错误,它将不会被导入,您可能会使用 settings.py 中的默认设置运行,这是您不希望的。例如,如果 settings.py 连接到产品数据库。最好总是需要一个 local_settings.py 并在找不到时抛出错误。
      猜你喜欢
      • 1970-01-01
      • 2019-04-10
      • 2014-05-19
      • 1970-01-01
      • 2012-07-05
      • 2011-11-04
      • 2023-03-23
      • 1970-01-01
      • 2012-11-23
      相关资源
      最近更新 更多