Booleans with default don't respect Environment Variable
Issue:
I would like to have a flag determining whether django-debug-toolbar should show up. I tried multiple options provided in the docs but my value still ends up being False. I am using a .env per your example.
Approach:
- Set a settings variable defaulting to False:
DEBUG_TOOLBAR_ENABLED = values.BooleanValue(False) - Set environment variable for local development in my DOTENV file (
.env):DJANGO_DEBUG_TOOLBAR_ENABLED=True(also triedtrue,"True",1, and"true")
Code
.env:
DJANGO_SETTINGS_MODULE=fuweb.settings
DJANGO_CONFIGURATION=Development
DJANGO_ALLOWED_HOSTS=*
DJANGO_SECRET_KEY=1234
DJANGO_DEBUG_TOOLBAR_ENABLED=true
settings.py:
class Common(Configuration):
PROJECT_DIR = Path(__file__).parent
BASE_DIR = PROJECT_DIR.parent
DOTENV = Path.joinpath(BASE_DIR, '.env')
SECRET_KEY = values.SecretValue()
DEBUG = values.BooleanValue(True)
DEBUG_TOOLBAR_ENABLED = values.BooleanValue(False)
print('env var:', os.environ.get('DJANGO_DEBUG_TOOLBAR_ENABLED'))
print('settings var:', DEBUG_TOOLBAR_ENABLED)
Console output:
$ ./manage.py runserver
env var: true
settings var: False
To add to this, the Boolean values are cast correctly. Below is a BooleanValue class from django-configurations source code, I added print() statements for debugging.
class BooleanValue(Value):
true_values = ('yes', 'y', 'true', '1')
false_values = ('no', 'n', 'false', '0', '')
def __init__(self, *args, **kwargs):
super(BooleanValue, self).__init__(*args, **kwargs)
if self.default not in (True, False):
raise ValueError('Default value {0!r} is not a boolean value'.format(self.default))
def to_python(self, value):
normalized_value = value.strip().lower()
if normalized_value in self.true_values:
print(True)
return True
elif normalized_value in self.false_values:
print(False)
return False
else:
raise ValueError('Cannot interpret boolean value {0!r}'.format(value))
The output of my print() statements is correct as expected. But it seems like the settings file is evaluated before the value is pulled from the environment variable and cast to the correct Boolean value. That being said, you cannot rely on the Boolean value to use in conditional logic in settings. The code below never executes regardless of my environment variable value because it always uses the default value.
if DEBUG_TOOLBAR_ENABLED:
print('I swear, it is TRUE!')
Any suggestions?
@StriveForBest Checking here how does it work I saw that django-configurations does something like this:
#.env
DJANGO_DEBUG=False
# settings.py
import os
from configurations import Configuration, values
class Base(Configuration):
DEBUG = values.BooleanValue(True)
class Development(Base):
DOTENV = os.path.join(Base.BASE_DIR, '.env')
Turns into something like this at run time:
# settings.py
import os
from configurations import Configuration, values
class Base(Configuration):
DEBUG = values.BooleanValue(True)
class Development(Base):
DOTENV = os.path.join(Base.BASE_DIR, '.env')
DEBUG = False
So it is possible to use django.conf.settings .'
from django.conf import settings
if settings.DEBUG:
print(''I swear, it's true!)
@hugobrilhante That is not what I'm talking about, I mean relying on Boolean values withing the settings.py, even within the same settings class.
Understand. have you tried it environ_name
Understand. have you tried it environ_name
that doesn't help. i found two reliable ways. either using
if VAR_NAME.value:
pass
or put the logic into post_setup hook, like so (I believe this is the more correct way).
class Development(Common):
@classmethod
def post_setup(cls):
""" Set up django-toolbar. """
if cls.DEBUG_TOOLBAR_ENABLED:
cls.INSTALLED_APPS += [
'debug_toolbar',
]