How to build a complete web app with Django and CockroachDB

How to build a complete web app with Django and CockroachDB

CockroachDB is a distributed relational database that enables users to scale their application and production software without hardware limitations. CockroachDB Serverless is the fastest way to get started using this relational database. It only takes two steps: sign up using your GitHub account, then connect your cluster using the connection information relevant to your system’s operating system.

Integrating CockroachDB into a Django application is seamless thanks to its feature-rich object-relational mapping (ORM) that lets us interact with the database using a fluent object-oriented API.

In this article, we’ll explore how well CockroachDB and Django work together by building a simple application using the Django ORM to communicate with CockroachDB via CockroachCloud. Then we’ll deploy our application to Heroku.

The final application will be a game leaderboard that enables users to enter information about their gameplay, then store that data in a database. The user interface then retrieves this data to display information about which games the user played, for how many hours, and more.

It helps to be familiar with Python and Django when following along with this tutorial. It’s also important to note that the article uses Python 3.8 or Python 3.9 as the recommended Python versions. And, if you’d like to see the final files, the application’s source code is available via GitHub

How to set up CockroachDB & install Django

For this tutorial, we need to ensure we’re registered for a CockroachDB account

To start our application, we’ll begin by installing pip in our system to be able to install python packages. This documentation provides steps on how to install pip depending on the operating system being used. 

Next, we create a project directory called cockroachDB. While inside this directory, we create a virtual environment, venv, and activate it. Then we install Django, as shown below:

mkdir cockroachDB
cd cockroachDB
python3 -m venv venv
source venv/bin/activate
pip install django==3.2.9

Note that when creating a virtual environment, we need to use one of the following commands to activate the environment depending on the operating system we’re using:

  • Linux/macOS: use source venv/bin/activate
  • Windows: use \venv\Scripts\activate' if you’re using a cmd-based terminal, or '.\venv\Scripts\activate.ps1' if you’re running PowerShell

After setting up the application, we proceed to create a Django project called game and a Django app called core:

django-admin startproject game .
python3 manage.py startapp core

We need to remember to add the Django app to the installed apps list in the project’s game/settings.py file, as shown below:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core.apps.CoreConfig',       #Add
]

We first run python manage.py migrate to apply migrations. Then, we execute the application using python manage.py runserver, which serves the default Django application, like in the screenshot below:

default Django application

How to add CockroachDB (instead of SQLite)

Django uses SQLite by default, and even generates a new SQLite database when we create a new application. However, we want to use CockroachDB so we need to set up a cluster and create a database for our application to use. 

First, in our CockroachDB Serverless account, we go to the create your cluster page and select CockroachDB Serverless as our preferred type. Then, we create a cluster by clicking Create your free cluster on the clusters page. 

The other plan available is Dedicated, which is a premium-based plan with added functionalities that allow users to have multi-region capabilities. When creating a free cluster, we can choose to leave the default parameters as they are. These include Cloud provider, Regions, Spend limit, and Cluster name.

creating a free cluster

After creating our cluster, CockroachDB Serverless pops up a Connection Info box. There, we create a cluster connection with the default SQL user based on our operating system. We select the appropriate option from the Choose your OS dropdown menu.

Note that the Connection Info contains a password that will be provided only once. We need to be sure to save the password from this string, as we’ll use it later:

cockroach sql --url='postgres://<username>:<password>@<global 
host>:26257/<cluster_name>.defaultdb?sslmode=verify-full&sslrootcert=<certs_dir>/cc-c
a.crt'

Next, we download the CockroachDB client and CA certificates using the commands provided. It should look like the following example:

curl --create-dirs -o ~/.postgresql/root.crt -O 
https://cockroachlabs.cloud/clusters/<cluster-id>/cert

We use the command cockroach sql --url to connect to our database using the connection string we saved earlier. An example of the connection string is shown below: 

cockroach sql --url 
'postgresql://<username>:<password>@<serverless-host>:26257/defaultdb?sslmode=verify-full&sslrootcert='$HOME'/.postgresql/root.crt&options=--cluster=<cluster-name>-<tenant-id>'

We should see an output similar to this:

connect to our database using the connection string

Now, we create a database called game for our application in the prompt SQL shell. We do this with the following command:

> CREATE DATABASE game; 

Exit using the command using:

> \q.

Next, we create the certs folder in the root of our CockroachDB application with the following command:

mkdir certs

Then, we customize the root.crt file’s path by copying the file into the certs folder.

cp -p $HOME/.postgresql/root.crt /path/to/cockroachDB/certs

Next, we need to add the certs directory to a .gitignore file so our certificates won’t end up on GitHub.

First, we create the .gitignore file by entering the touch command in the project’s root directory via terminal:

touch .gitignore

Then, we add certs/ to the .gitignore file.

How to install dependencies for using CockroachDB with Django

To use CockroachDB with Django, we need to install a few dependencies using pip: django, psycopg2, dj-database-url, and django-cockroachdb. We also need to install additional dependencies we’ll use when deploying our application to Heroku: django-heroku, gunicorn, and whitenoise . We install them all at once with the command shown below:

pip install psycopg2-binary dj-database-url django-cockroachdb==3.2.1 django-crispy-forms django-on-heroku django-environ whitenoise gunicorn

After installing the dependencies, we use the command pip freeze > requirements.txt to create the requirement.txt file and list our application’s dependencies. 

Our requirements.txt file is as follows: 

asgiref==3.4.1
dj-database-url==0.5.0
Django==3.2.9
django-cockroachdb==3.2.1
django-crispy-forms==1.14.0
django-on-heroku==1.1.2
gunicorn==20.1.0
psycopg2-binary==2.9.3
pytz==2021.3
sqlparse==0.4.2
whitenoise==5.3.0

Ensure the major django-cockroachdb and django versions correspond. For example, django-cockroachdb 3.2.x is compatible with django 3.2.x.

Note that for this to work, we need to ensure we’ve created the virtual environment and activated it, just as we did earlier in this tutorial.

How to configure CockroachDB

There are three ways to connect our applications to CockroachDB: command line, connection string, or connection parameters. We’ll use connection parameters for this application.

Then, in the game/settings.py, we add the CockcoachDB database:

import os
import environ
import dj_database_url

# reading .env file
env = environ.Env()
environ.Env.read_env()

………………….


DATABASES = {
    'default': {
        'ENGINE': 'django_cockroachdb',
        'NAME': env('DATABASE_NAME'),
        'USER': env('DATABASE_USER'),
        'PASSWORD': env('DATABASE_PASS'),
        'HOST': env('DATABASE_HOST'),
        'PORT': env('DATABASE_PORT'),
    },
}

In the code above, we first import os, environ, and dj_database_url, as the database_url needs them. Then install env() by pip install django-environ and make it readable by creating an instance.

 The code places all database credentials in the game/.env file.

  • The SECRET_KEY is a requirement for Django when deploying to Heroku. 
  • The DATABASE_NAME is game, the database we created in the SQL shell. We copy the exact combination of the database name from the Connection info in the Connection parameters tab in our CockroachDB account. We first need to select the database name and change it from defaultdb to game in the Set up section in the Connection info dialogue box, like the screenshot below:

database credentials

  • The DATABASE_USER and DATABASE_PASS come from the connection string we saved earlier (the string we used to connect to the database).
  • The DATABASE_HOST we’ll use is free-tier7.aws-eu-west-1.cockroachlabs.cloud.
  • The DATABASE_PORT for CockroachDB is 26257.

The database port in the connection parameters is shown below:

The database port in the connection parameters

Here’s an example of the game/.env file:

SECRET_KEY="<secret_key>"
DATABASE_NAME="xxxx-xxx.game" # xxx-xxx is the combination from Connection parameter
DATABASE_USER="<database_username>"
DATABASE_PASS="<database_password>"
DATABASE_PORT="26257"
DATABASE_HOST="free-tier7.aws-eu-west-1.cockroachlabs.cloud"

How to build the game leaderboard web app

Now, we’ll implement a simple web application with a game leaderboard. The application has models, views, and templates. Models contain the fields and information about their contents. Views handle the logic for manipulating the models using requests and responses. The application renders the logic to templates that can output the result to the browser when the server runs.

Setting up the models

First, in the app’s cockroachDB/core/models.py file, we add a Game class:

from django.db import models

class Game(models.Model):
    """
    Game model class.
    """
    name = models.CharField(max_length=100)
    viewer_hour = models.PositiveIntegerField()
    hours_streamed = models.PositiveIntegerField()
    acv_num = models.PositiveIntegerField()
    creators = models.PositiveIntegerField()
    streams_num = models.PositiveIntegerField()

    def __str__(self):
        return f'{self.name}'

The magic string __str__() returns the game’s name instead of the class name when the user views the admin panel.

This humble class is the key to all of our application’s interactions with CockroachDB. Using the Game class, Django can create a migration that connects to our CockroachDB database and creates a table to store leaderboard data. 

Setting up the views

In the cockroachDB/core/views.py file, we import the Game model first, then create the views using Django class-based views. We create two views: one view lists the entries from the database and entries users submitted via the form, and the other is a create-view enabling users to enter some data using a form:

from django.shortcuts import render
from django.views.generic import ListView, CreateView
from .models import Game


class GameListView(ListView):
    """
    Class-Based View showing the user information and game details.
    """
    model = Game
    template_name = 'core/index.html'
    context_object_name = 'games'
    paginate_by = 10


class GameCreateView(CreateView):
    """
    Class-Based view detailing how to create user's information.
    """
    model = Game
    fields = ['name', 'viewer_hour', 'hours_streamed', 'acv_num', 'creators', 'streams_num']

The GameListView code above defines the template name and the context object name used to iterate template data. GameCreateView doesn’t have a defined template name. Instead, we use the default class-based views naming convention <app>/<model>_<viewtype>.html. The code above also specifies the form’s fields.

Setting up routing

Before creating the templates, we create a cockroachDB/core/urls.py file inside the app to route the views path. In the cockroachDB/core/urls.py, we import the views and implement them, like this:

from django.urls import path
from .views import GameListView, GameCreateView


urlpatterns = [
    path('', GameListView.as_view(), name='home'),
    path('new/', GameCreateView.as_view(), name='game-create'),
]

In the project’s game/urls.py, we pass the path of the apps urls.py by importing include and implementing it like this:

from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('core.urls')),
]

Creating the templates

To create the templates, we create a directory called cockroachDB/core/templates with a directory called core inside it.

Note that this architecture is a Django convention. We can make the templates with or without it, but it’s recommended to use it.

We start by creating the cockroachDB/core/templates/core/base.html template so other templates can inherit from it. 

In the cockroachDB/core/templates/core/base.html file, we can use Bootstrap 5, Font Awesome, and CSS for quick styling by importing them as a content delivery network (CDN). Then, we create the navbar and pass the template blocks to make it extensible. The code implementation is as follows:

{% load static %}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"/>
    <link rel="stylesheet" href="{% static 'css/core.css'%}">
    <title>Top Games LeadBoard</title>
  </head>
  <body>
    <!-- Navbar -->
    <nav class="navbar navbar-expand-lg bg-light navbar-light py-3 mb-5 fixed-top">
      <div class="container">
        <a href="{% url 'home'%}" class="navbar-brand" style="color: #4c7f99;">Top Games Leaderboard</a>
        <button
          class="navbar-toggler"
          type="button"
          data-bs-toggle="collapse"
          data-bs-target="#navmenu"
        >
        <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navmenu">
        </div>
      </div>
    </nav>
    <br>

    <!-- Showcase -->
    <div class="game-table mt-5">
      {% block content %}{% endblock content %}
    </div>

  </body>
</html>

The code above loads static so the application can access CSS that’s in the static folder.

Displaying the data

To display the user entries and database data, we create a table in the cockroachDB/core/templates/core/index.html file and iterate over the context class object. First, we need to extend the base.html file and pass the table in the template block, like this:

{% extends 'core/base.html' %}

{% block content %}

<table class="table table-hover">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">Name</th>
      <th scope="col">Viewer Hours</th>
      <th scope="col">Hours Streamed</th>
      <th scope="col">ACV</th>
      <th scope="col">Creators</th>
      <th scope="col">Streams</th>
    </tr>
  </thead>

  {% for game in games %}
    <tbody>
      <tr class="list-color">
        <th scope="row">{{page_obj.start_index|add:forloop.counter0}}</th>
        <td>{{game.name}}</td>
        <td>{{game.viewer_hour}}</td>
        <td>{{game.hours_streamed}}</td>
        <td>{{game.acv_num}}</td>
        <td>{{game.creators}}</td>
        <td>{{game.streams_num}}</td>
      </tr>
    </tbody>
  {% endfor %}

</table>

{% endblock content %}

Creating a form

We need to create a template form to add data to the application directly. The django-crispy-forms application helps make the form look great. First, we use the command pip install django-crispy-forms to install the form-controlling application via the terminal. Then, we add crispy_forms to the list of installed apps in the cockroachDB/game/settings.py file as shown below:

…….
# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'core.apps.CoreConfig',
    'crispy_forms',       #Add
]
…….

We also add the setting template pack below to the cockroachDB/game/settings.py file:

#setting template pack
CRISPY_TEMPLATE_PACK = 'bootstrap4'

Next, we add the following code to cockroachDB/core/templates/core/game_form.html to create the form:

{% extends 'core/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
  <div class="content-section">
    <form method="post">
      {% csrf_token %}
      <fieldset class="form-group">
        <legend class="border-bottom mb-4">Game Form</legend>
        {{ form | crispy}}
      </fieldset>
      <div class="form-group mt-2">
        <button class="btn btn-outline-info" type="submit">Submit</button>
      </div>
    </form>
  </div>
{% endblock %}

The code extends cockroachDB/core/templates/core/base.html as before, then loads crispy-forms tags and creates the form.

In a browser, the form looks like this:

Form for data

Improving the UI

An exemplary user interface (UI) design should have an icon on the navbar to add data to the application. The entries also need to be paginated, so we make these changes to the cockroachDB/core/templates/core/base.html file:

{% load static %}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"/>
    <link rel="stylesheet" href="{% static 'css/core.css'%}">
    <title>Top Games Leaderboard</title>
  </head>
  <body>
    <!-- Navbar -->
    <nav class="navbar navbar-expand-lg bg-light navbar-light py-3 mb-5 fixed-top">
      <div class="container">
        <a href="{% url 'home'%}" class="navbar-brand" style="color: #4c7f99;">Top Games Leaderboard</a>
        <button
          class="navbar-toggler"
          type="button"
          data-bs-toggle="collapse"
          data-bs-target="#navmenu"
        >
        <span class="navbar-toggler-icon"></span>
        </button>

        <!--Paginator & Icon -->
        <div class="collapse navbar-collapse" id="navmenu">
          <ul class="navbar-nav ms-auto">
            <li class="nav-item">
              {% if page_obj.has_previous %}
              <a href="?page={{ page_obj.previous_page_number }}" class="nav-link"><i class="fa fa-chevron-left"></i></a>
              {% endif %}
            </li>

            <li class="nav-item">
              <a href="#" class="nav-link">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</a>
            </li>
            <li class="nav-item">
              {% if page_obj.has_next %}
                <a href="?page={{ page_obj.next_page_number }}" class="nav-link"><i class="fa fa-chevron-right"></i></a>
              {% endif %}
            </li>
            <li class="nav-item">
              <a href="{% url 'game-create'%}" class="nav-link"><i class="fa fa-plus-circle"></i></a>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    <br>

    <!-- Showcase -->
    <div class="game-table mt-5">
      {% block content %}{% endblock content %}
    </div>

  </body>
</html>

A user can now add information using the form, and the application stores that information in the database. 

To further improve the UI, let’s create some CSS. In the app directory core, we create a folder called static. Inside this folder, we create another directory called css, then create a file called core.css:

mkdir static && cd static
mkdir css && cd css
touch core.css

In the core.css file we add the following CSS:

/* Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Abel&display=swap');
/* Navbar styles */
body {
  font-family: 'Abel', sans-serif;
  background: #fafafa;
  color: #333333;
}

.navbar-brand {
  font-weight: bold;
}

.game-table {
margin-bottom: 10%;
}
/* Game form */
.content-section {
  background: #ffffff;
  padding: 10px 20px;
  border: 1px solid #dddddd;
  border-radius: 3px;
  margin-bottom: 20px;
  font-size: 17px;
  margin-top: 20px;
  padding-bottom: 30px;
}

.list-color.td {
  color: #a2afb8;
}

Redirecting the user

After entering the data through the form, we want to redirect the user to the index page, where all the data is displayed. To implement redirection, we go to the core/models.py file and import the reverse function. Then, we add the function below to handle the redirect:

from django.urls import reverse

# ...existing code

# Handles redirect
    def get_absolute_url(self):
            return reverse('home')

Migrating the database

We’ve added all the code our application needs to run. All that’s left is to generate and run a migration that will make a table for our game data in CockroachDB.

Let’s migrate our database by navigating to our project’s root directory and running:

python manage.py makemigrations core  
python manage.py migrate

If we check in our database in the CockroachDB account, we can see our tables:

our tables

That’s it! We’ve created the database table and our app is ready. Start the development server by running the following command:

python manage.py runserver

We navigate to http://localhost:8000 in our web browser, where we’ll see an empty table. This is because we haven’t added any games to our database yet. Let’s do that now. 

We load http://localhost:8000/new to open the game creation form we added earlier. We add a few games, then navigate back to http://localhost:8000. We should see something like this:

the development server

How to deploy the app

To deploy your application to Heroku, we first need to ensure Heroku CLI is installed in our local system. Our application also needs a few dependencies to host it in Heroku: django-heroku, gunicorn, and whitenoise, which we installed earlier. Django doesn’t serve static files in production, so we’ll use whitenoise to enable this support.

Configuring dependencies

We create a file called Procfile in our project’s root directory and add web: gunicorn game.wsgi to the file (`game` is the project name). This specification shows that our application is a web application using gunicorn, a web server getaway.

In our game/settings.py file, we then add an import of django-heroku in the imports section at the top of our file:

#...existing imports
import django_on_heroku 

We also need to add django_on_heroku.settings(locals()) to activate Django-Heroku and STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') to configure our static assets. At this point, the settings.py file looks like this:

import os
import environ
import django_on_heroku
import dj_database_url
from pathlib import Path


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

# reading .env file
env = environ.Env()
environ.Env.read_env()

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
# DEBUG = os.environ['DEBUG']

DEBUG = True

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'core.apps.CoreConfig',
    'crispy_forms',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'game.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'game.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django_cockroachdb',
        'NAME': env('DATABASE_NAME'),
        'USER': env('DATABASE_USER'),
        'PASSWORD': env('DATABASE_PASS'),
        'HOST': env('DATABASE_HOST'),
        'PORT': env('DATABASE_PORT'),
    },
}

# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

USE_THOUSAND_SEPARATOR = True

THOUSAND_SEPARATOR=','

DECIMAL_SEPARATOR='.'

NUMBER_GROUPING=3


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

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

#setting template pack
CRISPY_TEMPLATE_PACK = 'bootstrap4'

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

django_on_heroku.settings(locals())

Creating the application in Heroku

Now that we’ve configured our dependencies, we head to the terminal and type the following commands to initialize Git and create our application:

git init
heroku login
heroku create djangocockroachdb

Creating the application in Heroku also makes a remote called heroku, where we need to push the application. To add and commit the changes, and push the application to Heroku, we type the following commands:

git add -A && git commit -m "feat: initial commit"
git push heroku main

By default, Git creates a branch named master, but you can change the name by using git branch -M main to a preferred name like main.

We add the deployed application’s link to the ALLOWED_HOSTS in the game/settings.py file, like this:

ALLOWED_HOSTS = ['djangocockroachdb.herokuapp.com']

Pushing the file to Heroku

Next, we add the file, commit, and push it to the remote heroku. An example of this is shown below:

git add -A && git commit -m "feat: update commit"
git push heroku main

First, we need to disable collectstatic by typing the command heroku config:set DISABLE_COLLECTSTATIC=1 and adding the variables declared in the .env file to Heroku using the heroku config:set option like this:

heroku config:set SECRET_KEY=<secret_key>
heroku config:set DATABASE_NAME=<database_name>
heroku config:set DATABASE_USER=<database_user>
heroku config:set DATABASE_PASS=<database_password>
heroku config:set DATABASE_PORT=26257
heroku config:set DEBUG=True
heroku config:set DATABASE_HOST=free-tier7.aws-eu-west-1.cockroachlabs.cloud

We can also add the variables directly to Heroku through the Config var tab by going to Settings in the Heroku dashboard. After adding our .env values, the Config var should look like this image:

add the variables directly to Heroku

Since we did not use CockroachDB’s Connection string when configuring the database, we need to perform database migrations to register our database schema, like this:

heroku run python manage.py makemigrations core
heroku run python manage.py migrate

To confirm if the app deployed without any errors, we run the command heroku open in the terminal. The output should be like this:

confirm if the app deployed

CockroachDB Serverless saves our data in the cloud so we can access our game leaderboard information from anywhere.

Next steps

We’ve now created a simple Django application using CockroachDB — via CockroachDB Serverless — as the database and deployed the application to Heroku. We don’t need to migrate our database when using CockroachDB’s connection string.

Now that you know how well Django and CockroachDB work together, you can improve your application by adding more fields or displaying information from multiple users. This code can also provide the foundation for any unique new application that stores and accesses information in a serverless database.

Sign up for a CockroachDB account to begin building your own Django web app backed by the CockroachDB Serverless database.

About the author

Rain Leander github link linkedin link

K Rain Leander is a systematic, slightly psychic, interdisciplinary community liaison with a Bachelor’s in dance and a Master’s in IT. An epic public speaker, they have disappeared within a box stuffed with swords, created life, and went skydiving with the Queen. Seriously. Rain is an active technical contributor with OpenStack, RDO, TripleO, Fedora, and DjangoGirls.

Keep Reading

How to build a serverless polling application

Very few traditions can melt the corporate ice as well as an ugly holiday sweater contest. Which is why, this past …

Read more
How to build a complete Next.js app with Vercel and CockroachDB

In this tutorial, we’ll create an app for coordinating social events. In the process, you’ll see how simple it can …

Read more
How to build a complete web app with Python and CockroachDB

In this article, we’re building a full-stack web app that simulates a game leaderboard. The idea is to make it as simple …

Read more