别再用`import settings`导入django settings了

起因

  • 记得之前刚开始写django项目时,用import settings导入settings,被老大叼了。当时也没怎么想,只是照做了。直到最近参与一个同事写的django项目中,发现了好的地方都是使用这种方式导入settings。这个其中的影响,不能说难受,只能说贼难受。。。为了成功说服他改掉这种写法,那我得先搞懂来不是,所以有了这篇文章。

对比

from django.conf import settings与import settings的区别。前者是从django模版导入settings,是django官方推荐的导入settings的方式,后者是从项目模块中导入settings。

  • "import settings"导入将在 sys.path 中找到的第一个名为 settings.py 的python模块。它只允许访问你定义的设置文件,所以,如果你试图访问一个没有在你的设置文件中指定,django又具备的默认设置( django.conf.global_settings ),你会得到一个错误。
  • django.conf.settings 不是一个文件,而是一个懒加载对象。当你使用 from django.conf import settings时,Django还会做其他检查。

影响

非预期的变量值

场景一

  • 本地开发时,经常需要使用manage.py在终端启动各种命令。指定非settings文件运行(如:settings_local.py),加载的仍然是settings.py中的配置。

    ini 复制代码
    python manage.py runserver --settings=proj.settings_local
    python manage.py migrate --settings=proj.settings_local
    python manage.py collectstatic --settings=proj.settings_local
  • 怎么影响到的

    • settings_local.py中全力引用settings.py的变量,然后对一些变量进行覆盖
lua 复制代码
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings_local')

场景二

  • 使用环境变量DJANGO_SETTINGS_MODULE指定settings时

源码分析

  • Django启动的时候,会使用setup方法,源码如下。因此每次启动时会执行" from django.conf import settings"代码,settings中配置加载到内存中。
python 复制代码
# django/__init__.py
def setup(set_prefix=True):
    """
Configure the settings (this happens as a side effect of accessing the
first setting), configure logging and populate the app registry.
Set the thread-local urlresolvers script prefix if `set_prefix` is True.
"""
from django.apps import apps
    from django.conf import settings
    from django.urls import set_script_prefix
    from django.utils.log import configure_logging

    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
    if set_prefix:
        set_script_prefix(
            '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME
        )
    apps.populate(settings.INSTALLED_APPS)
  • 使用wsgi启动时,也是间接调用django的setup方法。
python 复制代码
# django/core/wsgi.py 文件
def get_wsgi_application():
    """
The public interface to Django's WSGI support. Return a WSGI callable.

Avoids making django.core.handlers.WSGIHandler a public API, in case the
internal WSGI implementation changes or moves in the future.
"""
django.setup(set_prefix=False)
    return WSGIHandler()
  • 使用在manage.py在终端启动时,调用的是ManagementUtility对象的execute方法,其中有调用setup()方法
python 复制代码
# django/core/management/__init__.py
def execute_from_command_line(argv=None):
    """Run a ManagementUtility."""
    utility = ManagementUtility(argv)
    utility.execute()

循环引用

  • 如果在settings中引用其他模块时,又以项目文件方式导入settings,可能会导致循环引用。

懒加载

Django的懒加载(lazy loading)机制指的是在需要时才加载某些设置,而不是在应用程序启动时就立即加载所有设置。这种机制有几个重要的意义:

  1. 性能优化: Django的settings.py可能包含大量的配置项,但并不是所有配置项都会在应用程序启动时立即使用。通过懒加载,只有在需要时才加载相应的配置项,可以节省内存和启动时间,提高应用程序的性能。
  2. 如果不设置成懒加载,在顶层导入模块的能力与手动配置设置对象的能力不兼容

因此,如果直接在项目中导入settings文件,则不会具备这样的优点。

总结

这篇文章起源于对Django项目中导入settings方式的疑惑。对比了from django.conf import settingsimport settings的区别,后者从项目模块中导入settings,可能导致非预期的变量值。源码分析表明,Django启动时会使用内置模块加载settings配置,若项目中直接导入settings则无法享受到懒加载带来的性能优势。同时可能导致循环引用问题,非预期的变量值,甚至是报错。

引用

相关推荐
小码哥_常4 小时前
告别MySQL!大厂集体转投PostgreSQL,到底藏着什么玄机?
后端
FYKJ_20104 小时前
springboot校园兼职平台--附源码02041
java·javascript·spring boot·python·eclipse·django·php
刀法如飞5 小时前
Go数组去重的20种实现方式,AI时代解决问题的不同思路
后端·算法·go
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题】【Java基础篇】第30题:JDK动态代理和CGLIB动态代理有什么区别
java·开发语言·后端·面试·代理模式
swipe6 小时前
别再把 AI 聊天做成纯文本:从 agui 这个前后端项目,拆解“可感知工具调用”的流式 AI UI
后端·langchain·llm
GetcharZp6 小时前
GitHub 爆火!纯 Go 编写的文件同步神器 Syncthing,凭什么成为程序员的标配?
后端
hERS EOUS6 小时前
SpringBoot 使用 spring.profiles.active 来区分不同环境配置
spring boot·后端·spring
LucianaiB6 小时前
我用飞书多维表做了一个 AI 活动推荐智能体:每天自动催我别错过截止日期!
后端
铁皮饭盒7 小时前
第2课:5分钟!用 Trae AI 生成你的第一个后端服务(Bunjs + Elysia)
前端·后端·全栈
金銀銅鐵7 小时前
[git] 浅解 git reset 命令
git·后端