This article was originally published at: https://render.com/docs/deploy-django. It's recommended to read the linked version with improved syntax highlighting.
This guide will demonstrate how you can set up a local Django development environment, create a simple view, and deploy it to Render. The application will be configured to use a Render PostgreSQL database and will use Poetry to manage the Python virtual environment and project dependencies, though neither are requirements to deploy a Django project on Render.
The finished code for this example is available on Github and the sample app can be viewed here.
This tutorial starts with a bare-bones installation and explains all required code modifications, so it should be straightforward to adapt it to any custom configuration in your existing Django codebase.
Create a Django Project
In this step, we will set up a local development environment and create basic project structure.
We will assume our project is called mysite
and consistently use it throughout the code. Feel free to choose a different name, though it must be a valid Python package name.
Install Poetry
If you do not have Poetry installed, follow the Poetry installation instructions for your operating system. In most cases, you will simply need to run the following:
macOS/Linux:
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
Windows in PowerShell:
(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python
You may need to restart your shell to load the poetry
command into your PATH
. To verify the installation was successful, try running poetry --version
.
Create Project Structure
- Use Poetry to initialize your project directory:
$ poetry new mysite
Created package mysite in mysite
$ cd mysite
$ ls
README.rst mysite pyproject.toml tests
# We don't need the code for our package that was generated by Poetry, so:
$ rm -rf mysite tests
- In
pyproject.toml
, ensure the Python version requirement includes version3.7
, which is available on Render.
[tool.poetry.dependencies]
python = "^3.7"
- Add Django as a dependency.
$ poetry add django
- Create a Django project for your application.
$ poetry run django-admin startproject mysite .
You should end up with the following directory structure:
$ tree
.
├── README.rst
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── poetry.lock
└── pyproject.toml
1 directory, 9 files
At this point, you should have a fully-functional scaffolding for your new Django application! To verify, you can start the development server.
$ poetry run ./manage.py runserver
Create the Hello World Landing Page
In this section, you will create a simple Django application with a static view, template, and an example static file that showcases the basic steps in creating a page using Django. If you are only interested in learning how to deploy a sample Django project to Render, you can skip to the Update Your App For Render section and deploy an empty project.
If you wish to build something more complex, it's highly recommended to read the official Writing your first Django app guide.
Create the Render app
Now that your application environment (a Django project) is ready, you are ready to start working on the application itself.
Django projects are collections of applications, wired together to form a website. Django provides a number of built-in applications, with the admin site being a well-known example.
- To create your application, run the following command from the root directory of your project:
python manage.py startapp render
This will create a directory named render
with following contents:
$ tree render
render
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── __init__.py
├── models.py
├── tests.py
└── views.py
1 directory, 7 files
- You also need to inform Django about your new application. Open
mysite/settings.py
, find definition of theINSTALLED_APPS
setting, and add a reference to theRenderConfig
class at the beginning of the list:
# https://docs.djangoproject.com/en/3.0/ref/settings/#installed-apps
INSTALLED_APPS = [
'render.apps.RenderConfig',
'django.contrib.admin',
'django.contrib.auth',
...
]
Write Your First View
- In
render/views.py
add the following Python code:
from django.shortcuts import render
def index(request):
return render(request, 'render/index.html', {})
This is one of the simplest views possible in Django. It renders the render/index.html
template, which we will create in a later step.
- Create the
render/urls.py
file and add following code:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
This file will tell Django that you want your index
view be accessible from the root URL of your application.
- Configure the root project
urlpatterns
to point to theurls
module of therender
application. Openmysite/urls.py
, add an import fordjango.urls.include
, andinclude
your application's URLs:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('render.urls')),
]
- Create the
render/index.html
template you referenced earlier. Create a new filerender/templates/render/index.html
and add the following HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello Django on Render!</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
crossorigin="anonymous">
</head>
<body>
<main class="container">
<div class="row text-center justify-content-center">
<div class="col">
<h1 class="display-4">Hello World!</h1>
</div>
</div>
</main>
</body>
</html>
- Add a static file to your application. Download this image and save it as
render/static/render/render.png
:
- In your template, load the
static
module and reference the downloaded image:
{% load static %}
<!doctype html>
<html lang="en">
...
<body>
<header class="container mt-4 mb-4">
<a href="https://render.com">
<img src="{% static "render/render.png" %}" alt="Render" class="mw-100">
</a>
</header>
...
</body>
</html>
- You can now verify your app is working with the following command:
$ python manage.py runserver
Update Your App For Render
In order for your Django project to be ready for production, you will need to make a few adjustments in the application settings. You will update your project to use a Render PostgreSQL database instead of a SQLite database and configure WhiteNoise to serve your static files.
Go Production-Ready
Before deploying any serious application onto production environment, you need to ensure it's properly secured and configured. Django documentation provides a useful deployment checklist, which we will follow in this step.
- Open
mysite/settings.py
and find the declaration of theSECRET_KEY
setting. We do not want to store production secrets in source code, so we'll fetch it from an environment variable that we'll create later:
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY', default='your secret key')
- Find the declaration of the
DEBUG
setting. This setting should never be set toTrue
in a production environment. You can detect if you are running on Render by checking if theRENDER
environment variable is present in the application environment.
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = 'RENDER' not in os.environ
- When
DEBUG = False
, Django will not work without a suitable value forALLOWED_HOSTS
. You can get the name of your web service host from theRENDER_EXTERNAL_HOSTNAME
environment variable, which is automatically set by Render.
# https://docs.djangoproject.com/en/3.0/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []
RENDER_EXTERNAL_HOSTNAME = os.environ.get('RENDER_EXTERNAL_HOSTNAME')
if RENDER_EXTERNAL_HOSTNAME:
ALLOWED_HOSTS.append(RENDER_EXTERNAL_HOSTNAME)
If you add a custom domain to your Render app, don't forget to add your new domain to the list.
Configure Django for PostgreSQL
For convenience, we will add the DJ-Database-URL package, which allows us to specify databases in Django using connection strings. Render Databases automatically provide connection strings in their control panel, which we will then provide to our web service via the DATABASE_URL
environment variable. We will also need to add psycopg2 to the project.
- Run following command to add necessary dependencies to your project:
$ poetry add dj-database-url psycopg2-binary
- In
mysite/settings.py
, find declaration of theDATABASES
setting and modify it to look as follows:
# Don't forget to import dj-database-url at the beginning of the file
import dj_database_url
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': dj_database_url.config(
# Feel free to alter this value to suit your needs.
default='postgresql://postgres:postgres@localhost:5432/mysite',
conn_max_age=600
)
}
Static Files
Websites generally need to serve additional files such as images, JavaScript, and CSS. In Django, these files are referred to as static files and it provides a dedicated module for collecting them into single place for serving in production.
The built-in module only supports moving files from one place to another, relying on web servers such as Apache or NGINX to serve them to end users. On Render, the internet-facing web server is provided by default and we need a way to host static files using it. In this step, we will set up WhiteNoise which is a highly popular solution for this problem. The following instructions are a short brief of the procedure described in the WhiteNoise documentation.
- Add WhiteNoise as a dependency (adding Brotli support is optional, but recommended):
poetry add 'whitenoise[brotli]'
- Open
mysite/settings.py
, find theMIDDLEWARE
list, and add the WhiteNoise middleware just afterSecurityMiddleware
:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
...
]
- Find the section where static files are configured. Apply following modifications:
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
# This setting tells Django at which URL static files are going to be served to the user.
# Here, they well be accessible at your-domain.onrender.com/static/...
STATIC_URL = '/static/'
# Following settings only make sense on production and may break development environments.
if not DEBUG:
# Tell Django to copy statics to the `staticfiles` directory
# in your application directory on Render.
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# Turn on WhiteNoise storage backend that takes care of compressing static files
# and creating unique names for each version so they can safely be cached forever.
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Create a Build Script
- We need to run a series of commands to build our app. We can accomplish this with a build script. Create a script called
build.sh
at the root of your repository:
#!/usr/bin/env bash
# exit on error
set -o errexit
poetry install
python manage.py collectstatic --no-input
python manage.py migrate
Make sure the script is executable before checking it into Git:
$ chmod a+x build.sh
We will configure Render to call this script on every push to the Git repository.
- We are going to run our application with Gunicorn. Add the dependency to your project:
poetry add gunicorn
Commit all changes and push them to your GitHub repository. Now your application is ready to be deployed on Render!
Deploy to Render
There are two ways to deploy your application on Render, either by declaring your services within your repository using a render.yaml
file or by manually setting up your services using the dashboard. In this tutorial, we will walk through both options.
Use render.yaml
for Deployments
- Create a file named
render.yaml
in the root of your directory. The file will define your Django Web Service and the Database used by your application. Don't forget to commit and push it to your remote repository.
databases:
- name: mysite
databaseName: mysite
user: mysite
services:
- type: web
name: mysite
env: python
buildCommand: "./build.sh"
startCommand: "gunicorn mysite.wsgi:application"
envVars:
- key: DATABASE_URL
fromDatabase:
name: mysite
property: connectionString
- key: SECRET_KEY
generateValue: true
- key: WEB_CONCURRENCY
value: 4
- On the Render Dashboard, go to the YAML page and click
New From YAML
button. Select your application repository (give Render permission to access it if you haven't already) and clickApprove
on the next screen.
That's it! Your app will be live on your .onrender.com
URL as soon as the build finishes.
If you skipped the Create the Hello World Landing Page section, you will see a Not Found
error when visiting your site. You can verify your deploy was successful by visiting the admin dashboard at /admin
Manual Deployment
Create a new PostgreSQL database on Render. Note your database internal connection string; you will need it later.
Create a new Web Service, pointing it to your application repository (give Render permission to access it if you haven’t already).
Select
Python
for the environment and set following properties:
Property | Value |
---|---|
Build Command | ./build.sh |
Start Command | gunicorn mysite.wsgi:application |
- Add the following environment variables under Advanced:
Key | Value |
---|---|
DATABASE_URL |
The internal connection string for the database you created above |
SECRET_KEY |
Click Generate to get a secure random value |
WEB_CONCURRENCY |
4 |
That's it! Save your web service to deploy your Django application on Render. It will be live on your .onrender.com
URL as soon as the build finishes.
Create Django Admin Account
Once your application is live, create a new Django admin account by running the following command in the Render Shell:
$ ./manage.py createsuperuser
Top comments (3)
Haven't heard about Render before, but looks interesting. Let's say that you have "classic" Django setup - docker compose with several services (Django, PostgreSQL, Celery, Redis, RabbitMQ, Daphne for handling websockets) - what would be the breakdown of the pricing to host entire application? How would you deploy that? :)
Hey Mateusz!
The cost will be highly dependent on your resource requirements. From what you described, it seems like you would have:
One thing to call out where we are notably different from our competitors is that we don't currently have any limits on simultaneous connections or connection duration, including websockets!
Some of the other cool features that come with all Render services:
render.yaml
.You can look at our pricing page to get an idea of how much it would cost based on your resource requirements.
I hope this helps! If you have any more questions, feel free to drop a message in our Slack channel.
Awesome, thanks :)