Setting-up a Django project for production
Tags: django, dotenv, security, virtualenv
Published: 2021-10-05 06:43:24

Setting up a django project is an expertise worthy of mastery. This is pretty important because; lousiness can be permitted and forgiven, whilst developing locally. However, you would definitely pay dearly, if an attacker should trail your backend-system. This trailing becomes feasible, due to the fact that; confidential variables e.g SECRET_KEY, DATABASE_URL, STATIC_URL, MEDIA_URL or some confidential link etc, required to be kept secret; in a .env file, was mistakenly loosed in the production code. A single link being exposed, can give an idea into several other links or services, to an experienced attacker (cracker). Hence, a proper project setup, is of utmost priority, from the inception of the project. A great advantage to this, is that once setup, it becomes very easy to make reference, from whatever point or line of code in the project. However, this might feel cumbersome, while starting out. Nevertheless, this is unnegotiable as a matter of fact. I'll be working from a Linux environment and hence certain command-line commands will definitely be unique to the platform. You can always lookout for the analogical command specific to your platform. However, these commands will only be used when there are no alternatives. Onward then!
In sequence, let's outline the procedures:
a) <b>Create a folder</b>; I'll call mine projectTungsten
```
mkdir projectTungsten
```
b) <b>Python version</b>: for the moment, the most compatible python version recommended (on the basis of the required dependencies; pscopg2, django-heroku etc) for now, is python 3.8. If you've not got python 3.8 installed, get installed.
```
for Linux, open a terminal and run: 
a) sudo apt-get update
b) sudo apt-get install python3.8
```
If the above doesn't work, get on the AskUbuntu website and ask your question.
c) <b>Setting up a virtual environment</b>: since we would want to build with python3.8, it implies that our virtual environment must be created using python3.8. Hence, 'cd' (cd: change directory) into your projectTungsten
```
a) cd projectTungsten
b) python3.8 -m venv <environment name>
i.e python3.8 -m venv tungsten_admin
```
d) <b>Activating the virtual environment</b>: 
```
source tungsten_admin/bin/activate
```
If everything has been correctly implemented, the above command shows up on your terminal, with the environment name in parenthesis.
e) <b>Installing the required packages: the foremost packages required includes the following;
```
pip install psycopg2 gunicorn django-heroku python-dotenv django django-cors-headers
```
```
psycopg2: we'll be talking to a postgres database and require a database cursor to help us do so.
gunicorn: a Python WSGI server important, when our application goes live
django-heroku: we'll be pushing the app to heroku servers and this would aid in automatically configuring our Django application to work on Heroku.
python-dotenv: deal with environment variables
django-cors-headers: configure CORS policy
```
f) <b>Configure settings for development and production</b>:
in your project directory, cd into tungsten_admin; you'll find another folder: tungsten_admin as well. It contains settings.py, urls.py, wsgi.py etc. In this folder, create a new folder: settings. In this settings folder, create three new files: 
```
touch {base_settings,prod_settings,dev_settings}.py 
```
you could as well have renamed your default settings file as base_settings.py.
g) <b>Create a '.env' file </b>: this file should be cited in the same directory, with the manage.py file. Cut the "SECRET_KEY" in your base_settings.py file and paste in your .env file. This is where every secret detail; database, url, api keys etc should be kept.
h) <b> Create a '.gitignore' file </b>: this file should be cited in the same directory, with the manage.py file. In this file, add *.env, __pycache__, *.sqlite3 etc any other file you wouldn't want to commit to the repository.
i) <b>Resourcing manage.py and wsgi.py</b>: the manage.py file is used locally(in development), while the wsgi.py file, is same with the manage.py, however, is used in production by the server.
in your manage.py file, do:
``` 
"""Django's command-line utility for administrative tasks."""
import os
import sys
import dotenv

def main():
    """Run administrative tasks."""
    dotenv.load_dotenv(
        os.path.join(os.path.dirname(__file__), '.env')
    )

    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tungsten_admin.settings.dev_settings')

    if os.getenv("DJANGO_SETTINGS_MODULE"):
        os.environ["DJANGO_SETTINGS_MODULE"] = os.getenv("DJANGO_SETTINGS_MODULE")

    # print("\n\t Get env: ", 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()
```
in wsgi.py file, do:
```
import os
import dotenv

from django.core.wsgi import get_wsgi_application

dotenv.load_dotenv(
    os.path.join(os.path.dirname(__file__), '.env')
)

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tungsten_admin.settings.dev_settings')

if os.getenv("DJANGO_SETTINGS_MODULE"):
    os.environ["DJANGO_SETTINGS_MODULE"] = os.getenv("DJANGO_SETTINGS_MODULE")

application = get_wsgi_application()
```
in your .env file, ensure you have defined the variable:
```
DJANGO_SETTINGS_MODULE = tungsten_admin.settings.dev_settings
```
j)<b>Assigning variables</b>: in your dev_settings and prod_settings.py files,you should do
```
import * from base_settings
```
Then, define your development variables e.g database setup, static, media etc in the respective files as you prefer.

You can spin up your local server: python manage.py runserver

Like I said earlier,it's a tedious process; however, one that would bring back fruits greater than you could imagine. Let me know your difficulties and I'd be right on time to respond. Thank you.