The settings.py file in your project_name folder holds all the settings for your project, including debug mode,
database configuration, and template locations and should be kept up to date to ensure that your app works well.
Here I have outlined the sections of the file along with some common edits to the settings.py file specifically
to add functionality to your webapp as a repository of information. More information on how the app as a whole
needs to be updated for each functionality can be found in the following pages, often linked from their section
here. For a broader idea of what is happening, check out the other pages in this Django section, but to
troubleshoot issues, these updates to your settings.py file should be one of your first stops.
Each section of the settings.py file has a handy link to the Django documentation to help you customise your
webapp.
Layout of the settings.py File
Imports
The top of the file has only one import from the inbuilt python library pathlib, that Django uses in order to
locate files and directories without the need for using strings for the paths. This provides various
functionalities to the user including checking the existence of a path and checking if it is a path to a file
or directory. This section will expand as you find the need for more libraries as your project grows but it is
best practice to keep all the imports at the top of the file like this.
from pathlib import Path
Base Directory Definition
This definition of the BASE_DIR variable should not be altered.
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
__file__ refers to the current file; settings.py
.resolve() gets the absolute path of the file
.parent moves one level up the root directory, so .parent.parent moves two levels up
This final location acts as the base directory for your project
Security Key
This is a very important variable for your project. Django uses this secret key as part of the algorithm to
hash
user passwords, ensuring that user accounts remain safe, along with being used to create
CSRF tokens
and data validation tokens. If this is leaked, it would allow attackers to impersonate users, decrypt session
data, and forge authentication tokens or bypass CSRF protection or generate valid reset links.
If you have already pushed your project to GitHub, this value will be available to anyone looking through your
commit history, but that's not the end of the world as you can generate a new one. The
Django Secret Key Generator
can be used to create secret keys specifically for Django, matching their level of security.
It is best practice for reasons mentioned above to move this to your env.py file (or generate a new one and
move that).
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-random-letters-and-numbers'
Debug
You will find that when you create your project, the DEBUG variable is set to True. This is indispensable
throughout development, letting you, well, debug, any errors that may arise. However, for best practice, this
definition should be moved to your env.py file, allowing you have a debug mode on when making alterations
locally but having it turned off in the final deployed website.
Having DEBUG=True on a deployed site can cause the following issues:
Security Risks
The debug mode will display detailed error messages that help you when you build a website. However
the provided variables, database credentials, and file paths can be used by attackers to exploit
vulnerabilities.
Performance Issues
It's very handy to get detailed error reports when something goes wrong to help us pinpoint where
the issue is and apply a fix. However, the extra logging and error reporting consumes system
resources and can slow down your site which is not an ideal situation for your users.
Allowed Hosts
The ALLOWED_HOSTS variable is an added security measure that defines which host/domain names that your Django
application can serve, thereby preventing HTTP Host header attacks. This is a Python list of strings, so we can
now add either 'localhost' or '127.0.0.1' to this variable (or both) to cover our development and add your
deployed domain when the site goes live.
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
Installed Apps
The INSTALLED_APPS section defines the list of applications that are active in your Django project and include
built-in Django apps, third part apps or custom apps. Apps will be discussed more in their own section
here
but for now it is best to know that this is where you add both downloaded apps and your own created apps in
order for them to work.
Adding an app to this list makes them visible to Django and help it assess changes when migrating and
automatically integrate app features.
In Django, the MIDDLEWARE setting is a list of middleware components that sit between the request and response
phases of a web request. They act as a series of hooks that process incoming requests and outgoing responses.
Each middleware can:
Process requests before views are called
Process responses before they're returned to the browser
Handle exceptions, redirects, authentication, security checks, etc.
Here are the default ones and their uses:
MIDDLEWARE = [
# Adds security headers (e.g., HSTS, SSL redirects)
'django.middleware.security.SecurityMiddleware',
# Enables session support using cookies
'django.contrib.sessions.middleware.SessionMiddleware',
# Adds standard behaviors (e.g., URL normalization, APPEND_SLASH)
'django.middleware.common.CommonMiddleware',
# Protects against CSRF attacks by enforcing CSRF tokens
'django.middleware.csrf.CsrfViewMiddleware',
# Associates users with requests using sessions
'django.contrib.auth.middleware.AuthenticationMiddleware',
# Enables temporary messages via Django's messaging framework
'django.contrib.messages.middleware.MessageMiddleware',
# Prevents the site from being embedded in iframes (defends against clickjacking)
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF
This setting tells Django where to find the URL configuration for your project. It will link to the urls.py
file in your project name folder with dot notation. E.g.
ROOT_URLCONF ='project_name.urls'
Will tell django to import project_name/urls.py
So when a request comes in, Django looks at the ROOT_URLCONF to find the correct urls.py file, loads the list
of urlpatterns inside that file and matches the incoming URL against the patterns to find the right view to run.
Templates
The TEMPLATES variable defines how Django handles rendering the HTML templates by defining the path to the
templates, which template engine to use and other settings for processing the templates.
Here is an outline of the keys In the TEMPLATES dictionary:
BACKEND:
Defines which template engine should use, with the default being
django.template.backends.django.DjangoTemplates which is the built-in template engine.
You can add third-part engines here such as Jinja2 with by replacing it with
django.template.backends.jinja2.Jinja2
DIRS:
This is a list of directories that Django looks in for templates. By default it is empty. When
adding directories here, the general syntax is
'DIRS': [os.path.join(BASE_DIR, 'templates')]
For child folders you can specify them like:
'DIRS': [os.path.join(BASE_DIR, 'templates', 'allauth')] which will look in the allauth folder
inside the templates folder in the root directory.
APP_DIRS:
If True, Django will also look for templates inside each installed app's templates folder.
If False, Django will only use the directories specified in DIRS
OPTIONS:
The most common setting here is the context processors that automatically add extra data to every
template, so you can define your own and include them in this list
WSGI_APPLICATION
This setting in settings.py tells Django where to find the
WSGI
application object that serves your project when it's deployed. It will be in the form of:
Django will look in your project folder, find the wsgi.py file inside that folder and call the Python object
defined inside wsgi.py.
The WSGI is a standard interface between your web server (like Gunicorn, uWSGI, or mod_wsgi), and your Python
web app (in this case, your Django project). When the server receives a request, it passes it to the
application object defined here. Django processes the request and returns a response through this same object.
Databases
Here we can define our databases, for local development it would be the SQLite3
RDBMS
but if you host your database on an external server such as PostgreSQL, you will need to define it here when
you deploy your app.
AUTH_PASSWORD_VALIDATORS
This setting defines the password validation rules Django uses when users create or change their passwords. It
is a list of rules Django uses to enforce strong, secure passwords in order to protect your users from weak,
common, or easily guessed passwords during registration and password changes.
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': (
'django.contrib.auth.password_validation.'
# Prevents passwords that are too similar to the user's personal info (e.g., username, email, first name).
'UserAttributeSimilarityValidator'
),
},
{
'NAME': (
'django.contrib.auth.password_validation.'
# Ensures the password is at least a minimum number of characters (default is 8, but you can customize this).
'MinimumLengthValidator'
),
},
{
'NAME': (
'django.contrib.auth.password_validation.'
# Blocks passwords that are too common or easily guessable (like "123456", "password", etc.).
'CommonPasswordValidator'
),
},
{
'NAME': (
'django.contrib.auth.password_validation'
# Rejects passwords made up of only numbers (e.g., "12345678").
'NumericPasswordValidator'
),
},
]
Each validator can also be configured with extra options. For example you can raise the minimum password length
to 12 characters.
These settings control how Django handles language, time, and localisation.
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
# Sets default language for your site
LANGUAGE_CODE = 'en-us'
# Se the default time zone for your project
TIME_ZONE = 'UTC'
# USE_INTERNATIONALIZATION. If True, enables Django's translation system
USE_I18N = True
# Enables Django's time zone support
USE_TZ = True
You can set USE_I18N to False if your site is only ever in one language and you want to skip translation
overhead.
Static Files
The pathway to your static files such as images and custom JavaScript code. We will update and expand this
section when adding our static files.
The DEFAULT_AUTO_FIELD controls the type of primary key field that Django automatically adds to your models when
you don't explicitly define one. BigAutoField is a 64-bit integer that auto-increments. It's used as the id
field (the primary key) by default when you define a model.
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
How Tos
Linking Your env.py File
Clearly any sensitive information such as secret keys should not be kept in your online repository, especially
if it is made public. Therefore, linking your settings.py file to your env.py file is imperative to keep good
practices and a high level of security to your site. Information on setting up your env.py file can be found
here.
Update the settings.py file imports to include:
import os
We used this built in python module to define the environmental variables in our env.py file and will need it
in our settings.py file to retrieve them. To keep to good practices, add this below the other imports at the
top of the settings.py file.
Then under the other imports make a check for the env.py file and if found import it. The if statement is used
so that when we deploy, Django will obviously not have access to our local file which would result in an error
if we did not include this check for it first.
# If in developer mode and there is an env.py file
if os.path.exists("env.py"):
import env
Then update your SECURITY_KEY, getting the value defined in your env.py file.
SECRET_KEY = os.getenv('SECRET_KEY')
This makes it look for the value of SECRET_KEY in the env.py file. The second instance of SECRET_KEY in this
line refers to the name you have given to the variable in your env.py file because the os.getenv function it
will look through your env.py file for the variable that matches whatever is used as the argument. For example
if you named it something else like PASSCODE, your updated settings.py SECRET_KEY will look like:
SECRET_KEY = os.getenv('PASSCODE')
Update your debug DEBUG.
if "DEVELOPMENT" in os.environ:
DEBUG = True
else:
DEBUG = False
This check allows the Django to launch in debug mode when working locally with access to your env.py file
providing you a better time of debugging and then automatically switch to DEBUG = False when deployed,
providing the user with the best user experience.
Adding Apps
When you have created an app, add it to the list of INSTALLED_APPs like so:
Django
allauth
requires significant changes/additions to your settings.py file depending on the functionality that you want to
introduce.
Context Processors
Context Processors are used to inject additional variables into every template context and can be registered by
appending it to the context_processors key of the OPTIONS dictionary of the TEMPLATES dictionary with the
syntax of
app_name.file_name.function_name.
Such as
here
where I add the media_url function to add the variable MEDIA_URL to each template by appending
'core.context_processor.media_url'.
These are included by default so no changes should be required here.
INSTALLED_APPS = [
'django.contrib.messages',
# other apps...
]
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# other middleware...
]
You can overwrite the default values like so:
from django.contrib.messages import constants as message_constants
MESSAGE_TAGS = {
message_constants.DEBUG: 'debug',
message_constants.INFO: 'info',
message_constants.SUCCESS: 'success',
message_constants.WARNING: 'warning',
message_constants.ERROR: 'error',
}
Or even make custom messages:
message_constants.SUCCESS: 'green-toast'
Static and Media Files
To ensure that Django can find your CSS, JS, and media files, you will need to make sure that the paths are
defined in settings.py correctly. This can be done under the Static files section.
Add in the Cloudinary variables from your Cloudinary dashboard. I keep these at the top of the Static files
section. For security you should define these in your env.py file and access them from there.
# Import gettext_lazy at the top using the shorthand of _
from django.utils.translation import gettext_lazy as _
In the Internationalization section, add a LANGUAGES variable which will be a list of tuples. The tuples will
be the language code as a string and the gettext_lazy of the language name. Then update your LANGUAGE_CODE
variable to show the default language that you want for your website and add a LOCALE_PATHS to have the pathway
of the stored location. We have not created this folder yet but the accepted name is 'locale'.
LANGUAGES = [
('en', _('English')),
('ka', _('Georgian')),
]
LANGUAGE_CODE = 'en'
LOCALE_PATHS = [
BASE_DIR / 'locale', # Path where translation files will be stored
]
#Make the following True:
USE_I18N = True
USE_L10N = True
USE_TZ = True
Add locale middleware to middleware. It needs to go after sessions (.SessionMiddleware) because it will run in
a session but above common (.CommonMiddleware) because common deals with the URL and we will set up the URLs
depending on the language.