Where to verify the settings during startup - django

After settings.py executes, I need to check to make sure all the settings were found from the .env variables, and error out if they are not. Where's the appropriate place to put that logic? Right in settings.py? manage.py?

`i would advice you django-environ, check documentation at https://django-environ.readthedocs.io/en/latest/
once put in via pip install django-environ, create .env go into the foundation of your project:
in /.env
After that inside settings.py, you can use your predefined environment variables like:`
import os
# django-environ
# https://django-environ.readthedocs.io/en/latest/
import environ
from django.utils.translation import ugettext_lazy as _
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Load and read .env file
# OS environment variables take precedence over variables from .env
env = environ.Env()
env.read_env(os.path.join(BASE_DIR, '.env'))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env.bool('DEBUG', False)```

Related

Even though django-environ is set up correctly, why does Django give the error The SECRET_KEY setting must not be empty?

The open source project I'm developing uses Docker to use multiple env files, but I need to run the project without Docker.
Although I set django-environ correctly, I get the error "The SECRET_KEY setting must not be empty"
Does anyone have a solution?
I also added this part of the code to the settings
import environ
env = environ.Env(
# set casting, default value
DEBUG=(bool, False)
)
# Take environment variables from .env file
environ.Env.read_env(os.path.join(BASE_DIR, '../docker/dev/docker.env'))
But still it gives the following error
raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.
django-environ is a good choice for this purpose and you choose a good way to make your variables environment variables.
I think your settings.py module should be like the below code snippet:
import environ
import os
env = environ.Env(
# set casting, default value
DEBUG=(bool, False)
)
# Set the project base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Take environment variables from .env file
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
# False if not in os.environ because of casting above
DEBUG = env('DEBUG')
# Raises Django's ImproperlyConfigured
# exception if SECRET_KEY not in os.environ
SECRET_KEY = env('SECRET_KEY')
# Parse database connection url strings
# like psql://user:pass#127.0.0.1:8458/db
DATABASES = {
# read os.environ['DATABASE_URL'] and raises
# ImproperlyConfigured exception if not found
#
# The db() method is an alias for db_url().
'default': env.db(),
# read os.environ['SQLITE_URL']
'extra': env.db_url(
'SQLITE_URL',
default='sqlite:////tmp/my-tmp-sqlite.db'
)
}
CACHES = {
# Read os.environ['CACHE_URL'] and raises
# ImproperlyConfigured exception if not found.
#
# The cache() method is an alias for cache_url().
'default': env.cache(),
# read os.environ['REDIS_URL']
'redis': env.cache_url('REDIS_URL')
}
The error you've gotten is about missing SECRET_KEY in your .env file so your .env file for above settings should have below variables:
DEBUG=False
SECRET_KEY=your-secret-key
DATABASE_URL=psql://user:un-githubbedpassword#127.0.0.1:8458/database
SQLITE_URL=sqlite:///my-local-sqlite.db
CACHE_URL=memcache://127.0.0.1:11211,127.0.0.1:11212,127.0.0.1:11213
REDIS_URL=rediscache://127.0.0.1:6379/1?client_class=django_redis.client.DefaultClient&password=ungithubbed-secret

Django os.getenv('SECRET_KEY') throwing "The SECRET_KEY setting must not be empty."

I'm setting up Django using os.getenv to prepare it for deploying using Docker but it seems it is not reading the .env file. Any idea why is not reading it?
Here is the setup:
.env
SECRET_KEY=foo
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
settings.py abstraction
import os
from pathlib import Path
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = os.getenv('DEBUG')
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS')
You can use python-decouple to get the environment variable stored in the root of your project in a .env file.
from decouple import config
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
EMAIL_HOST = config('EMAIL_HOST', default='localhost')
EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int)
Note: for changes to apply you need to restart the server.
I'm using python-dotenv in order to implement dotenv functionality. If you want Django to find your .env file, you need to modify manage.py and wsgi.py files.
# manage.py
import os
import sys
import dotenv
def main():
"""Run administrative tasks."""
# dotenv settings
dotenv.load_dotenv(
os.path.join(os.path.dirname(__file__), '.env')
)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
if os.getenv('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = os.getenv('DJANGO_SETTINGS_MODULE')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
# wsgi.py
import os
import dotenv
from django.core.wsgi import get_wsgi_application
# dotenv settings
dotenv.load_dotenv(
os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env')
)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
if os.getenv('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = os.getenv('DJANGO_SETTINGS_MODULE')
application = get_wsgi_application()
When deploying via docker-compose, you can specify in the docker-compose file.bml in the container settings [web]:
web:
...
env_file:
- ./.env
It worked for me without using additional packages. In my case , the file .env is located in the directory where docker-compose.yml is located
To get environment variables from docker or from the AWS Elastic Beanstalk i use
os.environ.get('SECRET_KEY'), this is generally more reliable than os.environ['SECRET_KEY']

Can't connect .env file of smtp details to django

settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = os.environ.get('EMAIL_HOST')
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
.env
export EMAIL_HOST_PASSWORD=<>
export EMAIL_HOST_USER = <>
export EMAIL_HOST=<>
3.Termial
(Carealenv) E:\atom data\mywebsite>source .env
'source' is not recognized as an internal or external command,
operable program or batch file.
I am having error of SMTPserverdisconnected .. please run connect first
I want to connect my .env file to django so that SMTPServer get connected and i can send verfication email to users. It will be great help.. Thank you
Further to ruddra's answer, you can alternatively use python-dotenv.
pip install python-dotenv
then in your settings.py
# settings.py
from dotenv import load_dotenv
load_dotenv()
Then you can use the getenv or as you have in your example environ.get function from the built-in os module to grab env variables and provide defaults if they do not exist.
from os import getenv
EMAIL_HOST = getenv('EMAIL_HOST', 'localhost')
Where localhost is whatever you wish to set as default.
You can't use source in Windows machine as described in the Stackoverflow answer.
If you want to use .env file, consider using libraries like django-environ which will read the file directly, no need to load it from ENVIRONMENT Variables.
Sample usage in settings.py:
import environ
env = environ.Env(
# set casting, default value
DEBUG=(bool, False)
)
# reading .env file
environ.Env.read_env()
# False if not in os.environ
EMAIL_HOST = env('EMAIL_HOST')
Another alternative solution is to use Docker with docker-compose, where you can load the environment variables from file.

Wagtail settings only use .dev

I do not understand how to alternate between production and dev settings. Wagtail docs do not cover it and the only wagtail tutorial I can find mentions it and then completely skips over it. There is a settings file:
--| settings
----| __init__.py
----| base.py
----| dev.py
----| production.py
----| .env
my init file:
import os
from os.path import join, dirname
from dotenv import load_dotenv
dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)
ENV = os.environ.get('AMSS_ENV')
if ENV == 'dev':
from .dev import *
elif ENV == 'prod':
from .production import *
AMSS_ENV is set to 'prod'. I also have the DJANGO_SETTINGS_MODULE variable set to production in the .env from a different attempt. Does the init file not fire first? is my logic broken? I get no errors and everything works but it loads in dev every time. I've tried so many other things and it just sticks like this. Can someone tell me what am I supposed to do? or where I can look?
It is always useful to check wsgi.py and manage.py to see which settings file they are set to. It is very easy to accidentally serve or run commands with the wrong settings file by forgetting about these two files.

django project root self discovery

Ok so I recall there are some commands you could put in the settings.py file so that basically when you move your django project to another directory it won't get foo-bar'd up.
I know I could just do this by having a string variable everywhere it mentions the home directory but is there a more elegant way of doing this?
The architecture of a project in Django
root/
app1/
app2/
...
main/
settings.py
Inside settings.py:
SITE_ROOT = os.path.dirname(os.path.realpath(__file__)) -> gives the path of the file settings.py: root/main/. This is NOT THE ROOT OF THE PROJECT
PROJECT_PATH = os.path.abspath(os.path.dirname(__name__)) -> gives the root of the project: root/. This is THE ROOT OF THE PROJECT.
Django 1.8 already includes the project root directory as BASE_DIR:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
And you can use it in your app by importing settings:
from django.conf import settings
...
...
print(settings.BASE_DIR)
Grab the __file__ global, and use the various functions in os.path on it.
import os.path
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
PROJECT_PATH = os.path.abspath(os.path.dirname(__name__))