How to Deploy a Python Django Application using PlanetScale and Koyeb Serverless Platform
Tags: python, tutorial, django, webdev
Published: 2021-09-10 07:17:52


## Introduction

Django is a popular and powerful framework for Python application developers. Django comes with many features like authentication, content administration, an Object-Relational Mapper (ORM), and much more.
Django supports various relational databases including MySQL which makes it possible to run a Django application using the PlanetScale database serverless platform without having to perform any changes in your application.

In this guide, we will create a Django application, configure our project to use a PlanetScale database, and deploy the application on the Koyeb Serverless Platform using git-driven deployment.

Using Koyeb git-driven deployment, your Koyeb application is linked to your GitHub repository and each time changes are pushed to your repository, your application is being redeployed automatically by Koyeb.

At the end of this guide, you will have a working Django application running on Koyeb.

## Requirements

To successfully deploy a Django application on Koyeb, you need:
- Python installed on your machine
- A [Koyeb account](https://app.koyeb.com) to deploy and run the Django application
- A [PlanetScale account](https://planetscale.com) to run the database our application will use
- A [GitHub account](https://github.com/) to store your application code and deploy your application on Koyeb via GitHub

## Steps

To complete this guide to have a Django application running on Koyeb, you need to follow these steps:

1. [**Create a virtual environment**](#create-a-virtual-environment)
2. [**Create a new Django application**](#create-a-new-django-application)
3. [**Configure Django to use a PlanetScale database**](#configure-django-to-use-a-planetscale-database)
3. [**Deploy the Django application on Koyeb**](#deploy-the-django-application-on-koyeb)

## Create a virtual environment

Before creating the Django application, we will create a virtual environment also known as a virtualenv. Virtual environments allow you
to create an isolated Python environment to avoid interfering with the Python's system packages or other virtual environments.

To create a new virtual environment that we will use for our Django application, in your terminal run:

```bash
python3 -m venv ~/.venv/django-app
```

This command creates a new folder `django-app` in the `~/.venv` directory. The virtualenv contains a copy of the Python interpreter, pip, the standard library, and various supporting files.

We can now activate the virtualenv we previously created by running:

```bash
source ~/.venv/django-app/bin/activate
```

Once the virtualenv is activated, the virtualenv python and pip executables are added into your shell’s PATH.

## Create a new Django application

Let's start by creating a dedicated folder for our app and moving into it:
```bash
mkdir django-on-koyeb
cd django-on-koyeb
```

Before creating our Django application, we need to install:

- django, to install the Django framework and libraries
- dj-database-url, a Django utility that allows to parse DATABASE_URL.
- gunicorn, a pure-Python HTTP server for WSGI applications that can run multiple Python concurrent processes
- mysqlclient, the librairies to use MySQL or in our case Planetscale

> mysqlclient requires system librairies, please check
> https://pypi.org/project/mysqlclient/ for detailled instructions

In your terminal, execute the following commands to install the packages locally and save
these dependencies.

```bash
pip install django gunicorn dj_database_url mysqlclient
pip freeze > requirements.txt
```

Once the previous step is completed, you can create the Django application in
our local directory by running:

```bash
django-admin startproject django_on_koyeb ./
```

This command creates a `django_on_koyeb` directory in your current directory containing the following files:

```bash
├── django_on_koyeb
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py
```

### Prepare the Django application for production
Next, we will edit the `settings.py` file as we need to customize settings
related to security and performance for
our development and production environment.

Open the `settings.py` using your favorite editor, here nano:

```bash
nano django_on_koyeb/settings.py
```

We will edit the `settings.py` file to load some important settings of our application using environment variables.
To access and read environment variables, we need to import the `os` module.

```python
+import os
from pathlib import Path
```

Django also requires a `SECRET_KEY`. This key is used to provide cryptographic signing and should be set to a unique, unpredictable value.
By default, we will want to generate a random secret key when nothing is passed as an environment variable, i.e. when you are running in development mode.

To generate a random secret key, we will need to import `from django.core.management.utils import get_random_secret_key`:

```python
import os
+from django.core.management.utils import get_random_secret_key
from pathlib import Path
```

Search for the `SECRET_KEY = ...` line in the `settings.py` file and replace it as below:

```python
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', get_random_secret_key())
```

Now, when the `DJANGO_SECRET_KEY` environment variable is set, our application will use it. If no value is provided, the `get_random_secret_key()` function is called and will return a random secret key.

By default, the Django application runs in `DEBUG`. When deploying the application in production, for security and performance purposes `DEBUG` mode needs to be disabled. We will change the default value to disable DEBUG until it is explicitly enabled via the environment variable `DJANGO_DEBUG=True`.

```python
DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True'
```

Next, update the `ALLOWED_HOSTS` directive to read the `DJANGO_ALLOWED_HOSTS` from the environment. `ALLOWED_HOSTS` is required to contain the list of strings representing the host/domain names that the Django application can serve.

```python
ALLOWED_HOSTS = os.getenv("DJANGO_ALLOWED_HOSTS", "localhost,127.0.0.1").split(",")
```

Last, go to the bottom of the file and add the following directive below `STATIC_URL`:

```python
STATIC_URL = '/static/'
+STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
```

This setting is used to set the directory from which we want to serve static files.
The first part of the Django configuration is done, we can move to the next step and configure Django to use a PlanetScale database.

## Configure Django to use a PlanetScale database

To use a PlanetScale database in our Django application, create a new database
from the PlanetScale [control panel](https://app.planetscale.com/) or using the
[CLI](https://github.com/planetscale/cli#installation) running:

```bash
pscale database create django-on-koyeb
```

Once the database is created, create a new database password for the main branch. On the PlanetScale control panel, click the **Connect** button and new password to generate a user and password to connect the database.
You can also perform this action using the PlanetScale CLI by running:

```bash
pscale password create django-on-koyeb main production-password
```

Keep these credentials in a safe place, we will need them when deploying our application on Koyeb.

On PlanetScale, the main database's schema is immutable and all changes must occur on a development branch. As we will need to perform a migration propagate our models into our PlanetScale database,
we need to create a new branch.

On the PlanetScale control panel, click the **New branch** button and name the branch migration. You can also perform this operation using the PlanetScale CLI running:

```bash
pscale branch create django-on-koyeb migration
 ```

Once the branch is created, create a new database password to access the branch. On the PlanetScale control panel, click the **Connect** button and new password to generate a user and password to connect the database.
You can also perform this action using the PlanetScale CLI by running:

```bash
pscale password create django-on-koyeb migration migration-branch-password
```

As PlanetScale uses Vitess behind the scenes, we need to use a custom database engine to make our Django application work with Vitess.
To retrieve the Vitess custom engine, clone the Vitess repository and copy the `custom_db_backends` directory in your Django application root folder:

```bash
git clone https://github.com/vitessio/vitess.git ~/vitess
cp -r ~/vitess/support/django/custom_db_backends ./
```

Next, open the Django application `settings.py`:

```bash
nano django_on_koyeb/settings.py
```

By default, Django is using an SQLite database, we need to edit the
`settings.py` to use a Vitess database and retrieve the configuration via the `DJANGO_DATABASE_URL` environment variable.
If the `DJANGO_DATABASE_URL` is not set, the application will raise the exception `DJANGO_DATABASE_URL environment variable not defined` when starting.
In the `settings.py` replace the following part:

```python
# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': BASE_DIR / 'db.sqlite3',
#     }
# }
if os.getenv("DJANGO_DATABASE_URL", None) is None:
    raise Exception("DJANGO_DATABASE_URL environment variable not defined")

DB_PARAMS = dj_database_url.parse(os.environ.get("DJANGO_DATABASE_URL"))
DB_PARAMS["ENGINE"] = "custom_db_backends.vitess"
DATABASES = {
    "default": DB_PARAMS,
}
```

Let's not forget to import the `dj_database_url` module we're using:

```python
import os
from django.core.management.utils import get_random_secret_key
+import dj_database_url
from pathlib import Path
```



You can now save and close the `settings.py`. Let's run Django migration to propagate the application models to the PlanetScale database. In the terminal run the following command:

```bash
DJANGO_DATABASE_URL=mysql://PS_USERNAME:PS_PASSWORD@PS_HOST:3306 python manage.py migrate
```

Replace the `PS_USERNAME`, `PS_PASSWORD`, `PS_HOST` values with the PlanetScale values you generated for the `migration` branch.

Then on the PlanetScale control panel, create a new **Deploy request** to propagate the schema changes performed on the `migration` branch to the production branch `main` and deploy it. You can also perform this operation using the PlanetScale CLI by running:

```bash
pscale deploy-request create django-on-koyeb migration
pscale deploy-request deploy django-on-koyeb 1
```

The application is now configured and ready to be deployed on Koyeb.

## Deploy the Django application on Koyeb

As the Django application will be deployed on Koyeb using Git, we need to initialize a new git directory for our Django project.
In your terminal run:

```bash
git init
```

To keep only necessary files in our repository, we will add a `.gitignore` file to exclude undesired files.

```bash
curl https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore > .gitignore
```

Then, execute the following command to add files to commit to your repository and commit the changes

```bash
git add .
git commit -m "Django app initial commit"
```

Open a new tab in your browser and go to [GitHub](https://github.com/). Create a new repository named `django-on-koyeb` and click the **Create repository** button.
Then, go back to your terminal and add GitHub as a remote repository by running:

```bash
git remote add origin git@github.com:YOUR_GITHUB_USERNAME/django-on-koyeb.git
```

Rename the repository default branch to main executing:

```bash
git branch -M main
```

Last, push your changes to the GitHub repository by running:

```bash
git push -u origin main
```

Everything is now ready to deploy the Django application on Koyeb.

Go to the Koyeb [control panel](https://app.koyeb.com) and click the **Create App** button.
Choose GitHub as a deployment method and choose the repository you previously created in the list and set `main` as the branch value.

Override the default **Run command** with the following value to get the application to run properly: `gunicorn --worker-tmp-dir /dev/shm django_on_koyeb.wsgi`

Then, in the **Ports** section change the default port from 80 to 8000 which is the default port our application is listening to.

In the **Environment variables** section:

1. Add an environment variable of type **Secret** with `DJANGO_DATABASE_URL` as the value and in the value section click **Create Secret** and name your Secret `django-db-url` and `mysql://PS_USERNAME:PS_PASSWORD@PS_HOST:3306` as value. Take care to replace PS_USERNAME, PS_PASSWORD, and PS_HOST with the PlanetScale password information you created for your main production branch.
2. Create a plaintext environment variable with the name `DJANGO_DEBUG` and value set to `True`. We need this to validate our application is running properly as it doesn't contain any routes at the moment.
3. Create a plaintext environment variable with the name `DJANGO_ALLOWED_HOSTS`
and value set to `django-on-koyeb-<KOYEB-ORG>.koyeb.app`

Give your App a name, for instance `django-on-koyeb` and click the **Create App** button.

Your application is now being built and deployed on the Koyeb serverless platform. Within a few minutes, you will be able to access your application by clicking your App URL: `https://django-on-koyeb-<KOYEB-ORG>.koyeb.app`.

## Conclusion

In this guide, we explained how to deploy a Django application on the Koyeb serverless platform with PlanetScale as the database backend for our application.
By deploying on Koyeb, your Django application is secured with native TLS encryption and benefits from all the Koyeb serverless features including autoscaling, auto-healing, and a high-performance edge network.

Thanks to the git-driven deployment feature offered by Koyeb, each time you push new modifications to your GitHub repository, a new deployment of your application occurs automatically.
This allows you to focus on your application code while Koyeb takes care of building, deploying your application, and ensure your service is always up and running.

If you have any questions or suggestions to improve this guide,
feel free to reach out to us on [Slack](https://slack.koyeb.com).