Production ready settings file: Simplest way to get it done.
Tags: django, python, webdev, productivity
Published: 2023-01-19 11:12:29

All django projects generated from the command line using the `django-admin startproject` command comes with a settings file, this file is where all the configuration for your django project is kept including database configuration, static files and even secret keys.

> A Django settings file contains all the configuration of your Django installation.  ~ [Django Docs](https://docs.djangoproject.com/en/4.1/topics/settings/)

Since all the settings are very fragile and most of the variables decleared in the file are meant to be kept private, it's important to modularize the settings file for convenience and ease in both production and local phases of the project.

Ultimate reason for modularization would be that, most of the variables on the file eg: DEBUG, ALLOWED_HOST, etc. Would have a different value in production compare to the ones declared for them in the local environment, it is there for important to separate the production settings from developmental level settings from start.

Modularizing a django settings is very simple and pretty straight forward if done with the style introduced in this guide, however, this guide does not include environmental variables set-ups as the plan is to keep the guide simple with just a chunk at a time.
I will be publishing another article in few days that would show a quick guide on environmental variable.
Let's dive in.

### Modularizing the django settings

The settings needs to be modularized for series of reasons, another of which is to keep our application safe and to reduce the workload of tweaking settings or forgetting to change some variables defined for local machine on production environment, which may prone our django project to series of injections.

- Creating a settings folder
The first step to take towards the modularizing concept is to create a settings directory in our main project directory, that is the directory that houses `wsgi.py`, `asgi.py` and `settings.py`, name the new directory: `settings`, then don't forget to add the `__init__.py` file so python would recognize this directory as a module. 
Move the existing `settings.py` file into the new settings directory and the path to settings file should look something like `project_name/project_name/settings/settings.py.`
This little change must have breached our project, to assert this run any management command eg `manage.py runserver` and you should get a `CommandError` stating that the settings file can't be found. 
To rectify this issue, you need to redefine the path to settings in the manage.py file.

You want to check this article on how you can: [Protect Your Sensitive Data: A Guide to .env Files in Django](https://dev.to/defidelity/protect-your-sensitive-data-a-guide-to-env-files-in-django-499e)

- modifying manage.py to accommodate the tweak
Navigate into the `manage.py` file and you should find the generic management template django generated with the `django-admin startproject` command, the `manage.py` file should look something like this:

```
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.settings')
    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()
```

You will have to modify the path to settings by changing the path to settings file, so the new path together with `manage.py` file would look something like this:

```
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.settings.settings')
    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()
```
If you run a management command now, it should run as normal.


- Modularizing settings for different environments

You want to start by creating two new files in the settings module/directory, one would be named local_settings.py and the other named production_settings.py for our local and production environments respectively.

Now you copy everything in the settings file into the two other file by pasting the code below in both of them.

`from .settings import *`

Line `import *` would copy everything in the settings file into the two of them meaning we now have two separate settings file for two environments and we have the generic settings file as base.

- Configurating management to run the correct setting file based on the environment
The most important concept here is to understand the key difference between the production environment and local environment, the variable `DEBUG` in django settings is what allows django to show path to errors, give details about errors and all available paths in a django application and it is meant to be set to `True` if you're in local environment so you can easily debug your code and `False` in the production environment so django would be able to throw appropriate error when needed and not cast all the secret details about the project.

Knowing this, you'll be using the `DEBUG` settings in the management file to configure django so that it would run the correct settings at the correct environmet.

See this article: [Ease your way into automated testing in Django](https://dev.to/defidelity/ease-your-way-into-automated-testing-in-django-c88).

The step to this is to import the base settings file and check if DEBUG is true, if it is, django run the local settings and if it's not, django run the production settings. So the code in the management file would look something like this:

```
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
from your_project_name.settings import settings

def main():
    """Run administrative tasks."""
    if settings.DEBUG:
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.local_settings')
    else:
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.settings.production_settings')
        
    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()
```
This is a clever way and you are now assured that django would always run the correct settings based off the environment you're, to affirm that this settings work, go into the base settings file and set the `ALLOWED_HOST=['*']`, then tweak the `DEBUG` variable from True to False, run the server with `manage.py runserver` command and you should see from the log on the command line that django runs the local settings when debug is `True` and it runs the production settings when it's `False`.
After modularizing the settings, the next big thing to do in order to keep the project safe is to set up environmental variables and keep the special variable values in them, hence the project would be always ready for production.

In conclusion, I hope you learn something even if it's significantly small, kindly follow me on [Linkedin](https://www.linkedin.com/in/amusat-haki/) for I share a link to my latest articles on it always.

Thanks for reading.