Deployment day, and it's Django. Where to start? We got a server we can SSH into, we got our code and endpoints, if any, ready to be consumed. Right here, we are going to look into the best practices in terms of developing our backend applications, or SSRs (if we were using Django templating). Through the process, we elaborate on the 'why's' of having a production-ready application as soon as we create our project as opposed to waiting on the completion of the whole development process. Why Now? For one, a good product is never really finished. There is always that one UI change, that one bug or logic discrepancy, or better yet, user feedback prompting a feature addition: our application must be getting some traction. Look at this in this way, would we wait till we got all our user feedback before optimizing our application for production? What about how we serve our media files? Would we still be serving it directly all through? Would we have passwords to our databases hardcoded? What if I add a feature or adjust a UI on my local setup? Would it break the main production app right off the batt? A pointer we are getting to is this: launch your application and make small incremental changes as you go. There is no 'Tadaaa! It works and will never break or be changed!' moment. If you were simply coding as though it was on your machine all through and waiting for the 'perfect' opportunity, you have to STOP. Stop it. Get your application and pipelines up as soon as you start the project. Be production-ready with 'Hello world!' Enough talk. Let us have something we can work with here. We create a virtual environment, install our dependencies, and have our boilerplate project. mkdir launch-ready launch-ready python -m venv .venv .venv/bin/activate cd source We've made the directory called , our intended application name. We've also created and activated the virtual environment. Go ahead and install Django and create the project while at it. launch-ready pip install django django-admin startproject LaunchReady . Our directory should now look like this: (.venv) launch-ready ➤ ls LaunchReady manage.py (.venv) launch-ready ➤ ls LaunchReady asgi.py __init__.py settings.py urls.py wsgi.py (.venv) launch-ready ➤ Running will give the default launch page for Django. python manage.py runserver Our application is up and running. To prepare for production, however, we have a couple of things to configure. Create Production and Development Settings: The directory has one setting file. Within this directory, we create yet another directory named and move our settings file into it, renaming it in the process to . LaunchReady settings base.py mkdir settings mv -i settings.py settings/base.py Create two additional files within the directory and name them - to contain development settings - and - to have production settings. Our directory ends up looking as below: settings dev.py prod.py (.venv) settings ➤ ls base.py dev.py prod.py Locally, on our development machine, we will opt for our local installation of MySQL. Go ahead and create a database and user then head over back for the next step. As with best practice in terms of version control, . Opt at all times, for the environment variables. To manage this, we create a file that will never make it past our local machine. Just to be sure, we add it to the file. never store your passwords in code .env .gitignore .env >> .gitignore echo We then, go ahead and install (to read the variables from the .evn file )and (a wrapper to interact with MySQL from Django). python-dotenv mysqlclient pip install python-dotenv mysqlclient Our development settings will look as below. dev.py dotenv load_dotenv LaunchReady.settings.base * load_dotenv() DEBUG = SECRET_KEY = os.getenv( ) DATABASES = { : { : , : os.getenv( ), : os.getenv( ), : os.getenv( ), : os.getenv( ) } } EMAIL_BACKEND = ALLOWED_HOSTS = [ ] from import from import # since it's running on my machine, show me the errors True "SECRET_KEY" "default" "ENGINE" "django.db.backends.mysql" "NAME" "DATABASE_NAME" "USER" "DATABASE_USER" "PASSWORD" "DATABASE_PASSWORD" "HOST" "DATABASE_HOST" # show mail messages on the terminal "django.core.mail.backends.console.EmailBackend" # run on every host. "*" So we have our environment variables being read from within the development settings, but where do we set these items. Simple. We create a file next to our settings. .env dev (.venv) settings ➤ ls -a base.py dev.py prod.py .env The file content? = =database_name =database_user =database_password =localhost SECRET_KEY 'django-generated-secret-key' DATABASE_NAME DATABASE_USER DATABASE_PASSWORD DATABASE_HOST We can have multiple ways with the database and secret key configuration. It is not linear. Note: For our production application, we take the example off of Heroku. This works the same as with any other server we might get, with one or two tweaks. We install - a python package that lets us read and perform actions on the database in the event it was on a separate platform or other from our main application. dj-database-url pip install dj-database-url This, we use in our production-ready settings as below: prod.py dj_database_url LaunchReady.settings.base * ADMINS = (( , ),) DEBUG = SECRET_KEY = os.environ[ ] ALLOWED_HOSTS = [ , ] DATABASES = {} DATABASES[ ] = dj_database_url.config(conn_max_age= , ssl_require= ) EMAIL_BACKEND = EMAIL_HOST = EMAIL_HOST_USER = os.environ[ ] EMAIL_HOST_PASSWORD = os.environ[ ] EMAIL_PORT = EMAIL_USE_TLS = import from import "Developer name" "Developer email" # always set this to false in production False "SECRET_KEY" "launch-ready-domain.com" "server-ip-address" "default" 600 True # ToDo: get an email host provider "django.core.mail.backends.smtp.EmailBackend" "smtp.gmail.com" "EMAIL_HOST_USER" "EMAIL_PASSWORD" 587 True As our is set to , we, instead of getting the error, want to get a notification via mail. This is especially so when one of our views returns an exception. In this case, we set the developer(s) responsible. DEBUG False not found ADMINS = (( , ),) "Developer name" "Developer email" As we have our Linux server up. We create persistent environment variables, this time, read from the bash configuration files, setting them in either, (for system-wide environment configuration), or in - for per-user configuration in case we have multiple. /etc/environment ~/.bashrc /etc/environment SECRET_KEY= DATABASE_URL= DJANGO_SETTINGS_MODULE= EMAIL_HOST_USER= EMAIL_PASSWORD= '' '' # this is common with heroku and can be set via the console or dashboard interface '' '' '' The only major difference from the previous development setting would be how we read our database configuration. DATABASES = {} DATABASES[ ] = dj_database_url.config(conn_max_age= , ssl_require= ) "default" 600 True This would be how we configure our application to read from an external database from our application server location. Let's try this run. Go to your shell and run your development server. Remember, we nested and split our settings. So to run anything while in development, we have to remind Django which settings we want to use. python manage.py runserver --settings=LaunchReady.settings.dev Our application default template is back up. For production, we would have it run as below. python manage.py runserver 0.0.0.0:8000 --settings=LaunchReady.settings.prod Launch your browser and head to . You should get the very same page as with your development environment. http://launch-ready-domain.com:8000 What Next? Of course, there's more in terms of deployment server settings and configuration, especially in terms of serving static files. This, however, can be left for the next hour. We touch base with this rather lengthy piece as we fuel up and do this further in the next, and yes, the code can be accessed right off repository. TheGreenCodes Till next time, TheGreenCodes Previously published here.