在运行时更改Django设置

72

我希望在管理员界面中公开一些(特定于应用程序的)设置,以便用户可以轻松更改它们,而且不必重新启动Django。

我该如何实现?

我查看了http://djangopackages.com/grids/g/live-setting/上的应用程序(顺便说一句,django-constance最有吸引力),但实际上,所有这些应用程序都是将值存储在数据库中,提供Web界面以进行更改并缓存。前两个功能已经内置于Django中,是吗?

我看到的最大缺点是,这些应用程序都不能代替旧位置(settings.py)中的设置,并要求我迁移到它们的记法,并且通常需要添加另一个上下文处理器来在模板中访问它们。

我可不可以只是这样做呢?

  1. 创建一个用于我的设置的模型(这使我拥有各种类型和验证)
  2. 实例化一个这样的对象以保存我的设置(这允许用户在管理员界面中编辑它们)-我可以像为其他模型一样导出默认值作为fixture
  3. 包装settings.py,以便它为我的设置执行数据库查询- http://www.loose-bits.com/2011/04/extending-django-settings-with-derived.html

从我当前天真的观点来看,我只看到以下缺点:

  1. 添加或更改可用设置需要模式迁移(south)-我可以接受这一点。
  2. 我有一个可能有多个实例但实际上只需要一个单例的模型。-在某些情况下,这实际上可能是一个有用的功能。
  3. 性能/缓存:查看http://code.djangoproject.com/svn/django/trunk/django/conf/,我必须在设置包装器和/或模型中放入一些巧妙的代码,以便模型更改会清除或更新缓存值。-看起来并不像火箭科学那么复杂。
  • 在另一个项目中进行相同的操作需要再次付出类似的努力。- 我认为在settings.py中只需使用一个单一的字典常量,保存模型名称和用于查找的字段名称即可。
  • 这样难道不是最好的两全其美的方式吗- 在运行时使用管理员(拥有其所有优点)、数据库后端、缓存,而且我的settings.USED_TO_BE_IN_SETTINGS_DOT_PY无需任何更改。我是否遗漏了什么?


    1
    如果你想像以前一样使用 django.conf.settings,那么除了篡改 Django 本身之外,你无法实现你想要的功能。你应该迁移至少调用设置(代码迁移)以使用外部库提供的设置对象。 - Torsten Engelbrecht
    你是指你的项目设置吗?是的,当然可以这样做,不过你仍然需要更改你的导入。如果你仍然使用 from django.conf import settings,它将会产生与之前相同的效果,也就是从django/conf/init.py中导入settings对象,这只是一个包装器,用于包装你的项目设置文件。它并不打算根据代码包装另一个对象。再次强调:除非你侵入Django本身。 - Torsten Engelbrecht
    2
    (供日后参考)问题中的URL已经失效,但是现在可以使用的URL是http://djangopackages.com/grids/g/live-setting/。 - Bouke
    今天有人发布了这个:https://github.com/amdorra/django-kvmodel - Danny W. Adair
    有没有人对管理员和经理设置的操纵有任何解决方案? - Bazinga
    显示剩余6条评论
    8个回答

    28
    据我所知,Django的设置应该是不可变的。这其中有很多原因,最明显的一点是Django不知道服务器的执行模型(prefork / multi-threaded)。
    此外,你不能从Django模型中加载设置本身,因为在使用ORM中的任何内容之前,需要先加载设置。
    所以,基本上你有两个解决方案:
    1. 通过使用任何较低级别的数据库访问机制来从数据库引导设置; 2. 或者只需在其他某个模型中定义设置并在需要时直接获取它们。
    第一种方法是一个极其巧妙的hack,我不建议使用。第二种方法更加直接和简洁,但需要你改变平常的习惯(从django.conf导入设置)。
    第二种方法可能是你链接到的第三方应用程序所实现的方法。

    感谢您的评论。尽管目前没有记录,但可以在运行时更改一些Django设置 - https://code.djangoproject.com/ticket/14628 - 我指的是真正的应用程序特定设置(考虑用于计算的业务策略、百分比、日期等)。我只想将它们分离出来。我提到的包装器的想法是,仍然可以使用django.conf.settings,尽管值存储在数据库中。 - Danny W. Adair
    嗨,我来晚了。但是有没有办法可以更改管理模块的一个特定设置变量?我的意思是当我打开管理模块时,该变量应为“true”,否则为“false”。 - Udit Hari Vashisht

    17

    谢谢Chuck,请看我的评论,回答André Caron的问题。文档已经声明了多年https://code.djangoproject.com/ticket/14628 - 在我个人的情况下(五年前发布的问题),我指的是我的应用程序特定设置,而不是Django内置设置。 - Danny W. Adair

    11

    DATABASES是一个字典。因此,您可以像操作字典一样进行操作:

    import django.conf as conf
    
    conf.settings.DATABASES['default']['NAME'] = 'novo_banco'
    

    4
    问题在于 Django 什么时候读取这个内容以创建 django.db.connections,因为如果在此之后,你将会与 ORM 不同步。 - JulienD
    1
    这只允许我在执行时间内进行编辑,而不能持久化。当我重新启动服务时,该值会返回到旧值。 - Cibrán Docampo
    3
    不推荐这样做。在Python中可以这样,但在Django中不应该这样做。Python允许你像访问"__foo"这样的方法,这些方法本意是“私有”的。虽然你可以这样做,但这并不好,你的代码会出现问题。Django设置被认为是不可变的。 - nerdoc
    它不起作用啊!我还在寻找另一个选项! - Kevin

    2
    说实话,当我分析他的代码时,我更加熟悉Django。在版本1.4.5中,他使用了以下模块:
    • myproject\manage.py

    • django\core\management__init__.py ## 方法 - execute_manager

    • django\conf__init__.py ## 类 - LazySettings; 属性 - _wrapped

    • django\utils\functional.py ## 类 - LazyObject; 重要方法 - new_method_proxy

    这是一种功能性的选择,但它也有其风险。在Python中,“_”将属性视为受保护的。
    from django.conf import settings
    
    settings._wrapped.INSTALLED_APPS = () ## *really work*
    

    在以下项目中:https://github.com/alexsilva/DJPlugins,您可以看到此变量在运行时被修改。该项目的想法已经实现。

    3
    修改全局变量(如设置)对单一进程可能是有益的,但如果您在运行带有多个工作进程的生产环境,则不足够好(每个进程都有自己的全局变量副本)。 - Iftah
    它帮助我进行测试,我需要删除属性以检查是否会显示缺失的引发,谢谢! - Thaian

    2

    看一下:https://bitbucket.org/bkroeze/django-livesettings *Django-Livesettings是从Satchmo项目中拆分出来的一个项目。它提供通过管理界面而不是编辑"settings.py"文件来配置设置的能力。

    也许对你有帮助。


    1
    请查看链接 https://djangopackages.org/grids/g/live-setting/,它列出了所有实现此功能的Django包,该链接在原帖中提到。 - Flimm

    0
    如果您在settings.py中有一个变量,并且希望随时更改它,有两种方法: 第一种是创建一个数据库表,然后为其创建一个序列化器,再创建一个视图集。每当您想要获取它时,可以向此视图集发送HTTP请求,然后检索数据。 第二种是使用缓存,它非常快速,并且类似于Angular中的localStorage。

    0

    您不能直接修改settings.py文件。 例如: 如果您想在运行时更改数据库,则应将数据库的配置分离。

    # Projecr_name/user_database.py
    user_database = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'name',
        'USER': 'admin',
        'PASSWORD': '111111',
        'HOST': '127.0.0.1',
        'PORT': '3306'
    },
    'user_db': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'user1',
        'USER': 'admin',
        'PASSWORD': '22222',
        'HOST': '127.0.0.1',
        'PORT': '3306'
    }
    }
    # Projecr_name/settings.py
    from .user_database import user_database
    ...
    DATABASES = user_database
    ...
    

    在你的逻辑视图中调用

    # view.py
    from ../Projecr_name/user_database import user_database
    class Some(...):
        def Some(request):
        user_database['user_db']['NAME']='user2'
    

    那么你可以使用这种方式在运行时更改任何设置


    -1
    你可以使用settings模块中推荐的.configure()方法:
    from django.conf import settings
    settings.configure(DEBUG=True)
    

    settings 模块具有额外的便捷功能。请查看文档


    6
    这将触发raise RuntimeError('Settings already configured.') - xyz
    1
    同 raise RuntimeError('设置已经配置。') - Kevin

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接