Opened 6 years ago

Closed 6 years ago

#29079 closed Bug (wontfix)

Django settings should not cache user wrapped settings

Reported by: Riccardo Di Virgilio Owned by: nobody
Component: Core (Other) Version: 1.11
Severity: Normal Keywords:
Cc: Adam Johnson Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

django 2.0 and 1.11 are breaking my custom settings.

I'm using settings.configure with a custom object that can change his properties if the environment is changing.
Starting from 1.11 the function LazySettings.__getattr__ is caching the values that are returned from the custom object that is provided by the user.

If all the custom object can do is to provide static values why I should use a custom object at all instead of a regular module?

In my view is an user needs to use a custom object as settings is because he needs advanced features that cannot be archived by a normal module.
It's very easy to add cache to all properties in a custom object if this is behavior the user needs, but is really hard to disable this (if not impossibile for the way this code is written).

If the staff is strongly against disabling the cache by default, can we at least add an option to disable it?

thanks.

Change History (5)

comment:1 by Tim Graham, 6 years ago

You should include a sample project or steps to reproduce the issue. Ideally, you could also bisect to find the commit where the behavior changed.

comment:2 by Riccardo Di Virgilio, 6 years ago

right ok this is a basic example:

from django.conf import settings

class CustomSettings(object):

    ENVIRONMENT = "production"

    @property
    def DEFAULT_FROM_EMAIL(self):
        if self.ENVIRONMENT == "production":
            return "info@company.com"
        return "my-personal-email@gmail.com"

obj = CustomSettings()

settings.configure(obj)

print(settings.DEFAULT_FROM_EMAIL, obj.DEFAULT_FROM_EMAIL)
obj.ENVIRONMENT = settings.ENVIRONMENT = "development"
print(settings.DEFAULT_FROM_EMAIL, obj.DEFAULT_FROM_EMAIL)

the output of this code on django 2.1 is :

info@company.com info@company.com
info@company.com my-personal-email@gmail.com

my claim is that this property should be computer each time is accessed.

is true that django documentation says that you cannot expect runtime mutations to work and propagate properly trough django framework, but still internally I do rely on this behavior: I have internal settings that are generated for different environments and when I deploy django on production i'm deploying the settings by mutating the environment string and computing all properties.

this cannot be done anymore with the new behavior.

comment:3 by Tim Graham, 6 years ago

Cc: Adam Johnson added
Type: UncategorizedBug

The change in behavior is due to #27625 (c1b221a9b913315998a1bcec2f29a9361a74d1ac). I doubt we'll revert the change to restore an undocumented behavior but I'll cc Adam, the author of that change, for his input.

comment:4 by Adam Johnson, 6 years ago

Yeah I don't think we should revert as it makes all settings access faster, noticeably so, as benchmarked by Instagram.

You could always set the setting to an object with dynamic behaviour on access e.g.

class DefaultFromEmail:
    def __str__(self):
        if settings.ENVIRONMENT == 'production':
            return 'info@company.com'
        return 'my-personal-email@gmail.com'

DEFAULT_FROM_EMAIL = DefaultFromEmail()

Or use the undocumented, but unlikely to change, django.utils.functional.SimpleLazyObject

comment:5 by Tim Graham, 6 years ago

Resolution: wontfix
Status: newclosed
Note: See TracTickets for help on using tickets.
Back to Top