12 minutes read

Once we create a Django project, it comes with a predefined directory structure and files. Let's recreate the project called smithee with the movies app inside it. To do so, write the following commands in the terminal/command line:

# create project 'smithee'
django-admin startproject smithee

# change the cwd to the newly created project folder 'smithee'
cd smithee

# create app 'movies'
python manage.py startapp movies

After executing the commands above, our project should have a structure like this:

smithee           <-- BASE_DIR      
    --> smithee                 
            -> __init__.py
            -> asgi.py
            -> settings.py    <-- settings.py file 
            -> urls.py
            -> wsgi.py
    --> manage.py
    --> movies

The settings.py file is the central one for configuring all Django projects. It is nothing else than a Python module with defined variables. All variables inside are constants, and according to PEP 0008 convention, they should be written with capital letters. In this topic, we will discuss things you can do with variables in the settings file.

BASE_DIR

The BASE_DIR variable refers to the base directory and points to the top hierarchy of any Django project. In our example, it is smithee.

This variable is always included in the Django settings file, and all other paths that we define in our project are relative to this base directory. You should use it if you want to manipulate the included files. For example, if you want to define the name for a log file, it can be LOG_FILE = os.path.join(BASE_DIR, 'smithee.logs').

Older versions of Django (for example, Django 2.2) use the os module to configure the base directory:

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Starting with Django 3.1, BASE_DIR is defined with the pathlib module as follows:

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

The pathlib module offers classes that represent filesystem paths with semantics appropriate for different operating systems. We won't get into details regarding the module, as this is beyond the scope of this topic. You can find more details on the Official documentation page.

DEBUG

As you probably know, Django comes with a built-in debugger that makes our life easier. To use the in-built debugger, set the DEBUG variable to True:

DEBUG = True  # this is the default value and is preferred only in the development phase

One of the first things to do before launching a Django application in the real world is to set DEBUG to False. Features like "Error Handling and Notification" or "Accessing Static Resources" change their behavior when the DEBUG variable is changed from True to False. Such changes are intended to increase project security.

ALLOWED_HOSTS

ALLOWED_HOSTS is a list with addresses of all domains that can run your project.

By default, this variable is set to an empty list [], and it can stay like this in the development phase because the default address will be 127.0.0.1 or localhost. If you switch to DEBUG=False, this variable can not be an empty list anymore. We will have to give hosts names, for example: ALLOWED_HOSTS = ["127.0.0.1", "movies.com"]. While 127.0.0.1 represents your computer, movies.com indicates that your application can be run on the domain with the corresponding name.

If you switch to DEBUG=False and ALLOWED_HOSTS is left empty, Django will refuse to serve requests and respond with HTTP 400 bad request instead.

SECRET_KEY

The SECRET_KEY variable is another security-related variable like ALLOWED_HOSTS. Unlike ALLOWED_HOSTS, which is empty by default, SECRET_KEY has a default value, for example like this:

SECRET_KEY = 'oubrz5ado&%+t(qu^fqo_#uhn7*+q*#9b3gje0-yj7^#g#ronn'

The purpose of this variable is to sign certain data structures digitally. Specifically, Django uses the SECRET_KEY on sensitive data structures like session identifiers, cookies and password reset tokens by default. However, you can use it to protect any sensitive data structure in your project.

You should be careful about exposing your project's SECRET_KEY. If you suspect for any reason that it has been compromised, replace it immediately.

Below is an example of how Django uses the secret key under the hood to sign sensitive pieces of information:

from django.core.signing import Signer

signer = Signer()

# generate a cryptographicaly signed value for the string "Sensitive data"
value = signer.sign('Sensitive data')

print(value)
# Sensitive data:GdMGD6HNQ_qdgxYP8yBZAdAIV1w

The signature is appended to the end of the string, right after the colon. By default, the Signer class uses the SECRET_KEY setting to generate signatures.

We won't delve into details regarding the Signer class; this is outside our topic. You can always refer to the Official documentation page.

INSTALLED_APPS

You already know that the INSTALLED_APPS variable is a list containing all apps that are used in a project. We have created an app called movies. To let Django know that the app exists, we have to add the app name at the end of the list with installed applications:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'movies', # don't forget to put it inside quotes and also add commas after every app
]

TEMPLATES

Django has a convenient way to generate HTML dynamically. The most common approach relies on templates. A template contains the static parts of the desired HTML output and special syntax that describes how dynamic content is inserted. To manage these files, Django makes use of template engines. Templates engines are configured with the TEMPLATES setting that represents a list of configurations for each engine:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "templates")],
        'APP_DIRS': True,
        'OPTIONS': {
            # other options here ...
        },
    },
]

BACKEND is a dotted Python path to a template engine class implementing the template backend API. The built-in backends are django.template.backends.django.DjangoTemplates (Official documentation) and django.template.backends.jinja2.Jinja2 (Official documentation).

Since most engines load templates from files, the top-level configuration for each engine contains two common settings:

  • DIRS defines a list of directories where the engine looks for template source files;

  • APP_DIRS tells whether the engine should look for templates inside the installed applications. Each backend defines a conventional name for the subdirectory inside applications where templates should be stored.

Lastly, OPTIONS contains extra parameters for a template backend. Available parameters vary depending on the template backend.

DATABASES

In Django projects, you employ SQLite databases by default:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

DATABASES is a constant dictionary of the database connection information. You can have connections to multiple databases, but usually, you will need the default entry. Take a look at possible options:

  • default is the default database connection configuration. You should always have a default set of connections settings;

  • ENGINE, in our case, tells Django to use the SQLite backend;

  • NAME will indicate the path to the database you want to connect to.

In addition to SQLite, Django also supports other popular databases: PostgreSQL, MySQL, and Oracle.

URL and ROOT variables

Websites generally deliver additional data such as images, videos, or style-related files such as CSS files. In Django, we refer to these files as media and static files. Django provides a pre-installed app to help you manage them. For that, we need to set up the URL and ROOT variables inside the settings file.

URL variables are either STATIC_URL or MEDIA_URL; they indicate paths relative to the BASE_DIR variable. In other words, think of this as a reference to static and media files, for example, http://127.0.0.1:8000/static/css/style.css. While STATIC_URL is used for reference to the static files (files responsible for the app style), MEDIA_URL will refer to any media file (audio, video, and so on).

ROOT variables indicate absolute paths. Like URL, they can be either STATIC_ROOT or MEDIA_ROOT. Their purpose is to retrieve static and media files. Think of this as the single root directory from where a Django application takes static and media files.

To configure URL and ROOT variables, add the following lines at the end of settings.py:

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Conclusion

The settings.py file is a small but very important and powerful part of any Django project. If it's incorrect, it can give you a lot of headaches during all development phases. But if you do it right, it will be a good basis for your project to grow and scale in the future. There are other points of the settings file that we haven't touched yet, but for now, let's practice what you've learned.

27 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo