HOW TO DEPLOY EXISTING DJANGO PROJECTS TO RENDER
Tags: programming, python, cloud, render
Published: 2022-09-02 21:43:18

In this post I would be demonstrating how to deploy an existing Django project to render, I noticed that the render documentation did not have a guide for persons with already existing projects at the time of writing this article.
the source code is available on github[here](https://github.com/jayjaytentacion/snipets-api)
And the live site [here](https://j-snippets.onrender.com)

## Prerequisites
Before you hop on, make sure you have created an account on [render](https://render.com/register) and have an understanding of Virtual environments and poetry, learn more about poetry [here](https://realpython.com/dependency-management-python-poetry/)


## Step 1 Getting started
Before we can proceed to deploy our application to render, we need to install poetry(a python package for managing dependencies and environments)

To install poetry run the following code in the terminal:
For Linux/macOS/gitbash

_shell_
`curl -sSL https://install.python-poetry.org | python`

For Windows in Powershell:

_shell_
`(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | python`

To verify the installation run the following command in the terminal:

_shell_
`poetry --version`

Update it:

_shell_
`poetry self update`


## Step 2 Deployment Setup

The Django app I would be deploying has the following folder structure 
![snippeteapi folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evaui1pbhp7mhqmcj57q.png)
the snippets directory is the project directory and the snippetsapi is the application directory

**Create a pyproject.toml file**
make sure your virtual environment is activated and you're in the root of your project 
run the following command in the terminal:

_shell_
`poetry init`

Fill in the prompts:

_shell_
```shell
Package name [snipets-api]:           #leave blank and tap enter
Version [0.1.0]:               #leave blank and tap enter
Description []:                #leave blank and tap enter
Author [okputu julius <juliusstan10@gmail.com>, n to skip]:   #leave blank and tap enter  
License []:  #leave blank and tap enter
Compatible Python versions [^3.10]:   #leave blank and tap enter

Would you like to define your main dependencies interactively? (yes/no) [yes] no       #enter no
Would you like to define your development dependencies interactively? (yes/no) [yes] no   #enter no

```
After filling all the prompts
a file named pyproject.toml would be created at the root of your project

_pyproject.toml_
```toml
#this  file contains details  and dependencies of the particular project
[tool.poetry]
name = "snipets-api"
version = "0.1.0"
description = ""
authors = ["okputu julius <juliusstan10@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.10"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

```

**Add dependencies to the pyproject.toml**

To add dependencies individually:

_shell_
`poetry add <package name>`

if the project already has a requirements.txt file
run the following code in the terminal:

_shell_
``poetry add `cat requirements.txt` ``


note: for windows use PowerShell or gitbash

A file  poetry.lock which contains details of the installed dependencies is created

_poetry.lock_
```lock
[[package]]
name = "asgiref"
version = "3.5.2"
description = "ASGI specs, helper code, and adapters"
category = "main"
optional = false
python-versions = ">=3.7"

[package.extras]
tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]

[[package]]
name = "certifi"
version = "2022.6.15"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
python-versions = ">=3.6"
......
```

**Set Environment Vars and Add Build script**
Navigate to your settings.py and add the following :

Don't forget to import os at the beginning of the file

_settings.py_
```python
import os
...

ALLOWED_HOSTS = ['*']

SECRET_KEY = os.environ.get('SECRET_KEY', default='your secret key')
DEBUG = os.environ.get('DEBUG',default=True,cast=bool)
```

Create a file build.sh at the root of your project, this would contain the commands that build the app

_build.sh_
```sh
#!/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

_shell_
`chmod a+x build.sh`

we're going to run our project using gunicorn, add the dependency to your project

_shell_
`poetry add gunicorn`


**Configure database and static Files**

Add the following packages

_shell_
```shell
poetry add dj-database-url psycopg2-binary #for database config
poetry add 'whitenoise   #for static files config
```

At the top of the settings.py file import dj-database-url 
update the databases dictionary with the snippet below and add the WhiteNoise middleware just after SecurityMiddleware

_settings.py_
```python
import dj_database_url
...

DATABASES = {
    'default': dj_database_url.config(        # Feel free to alter this value to suit your needs.        default='',        conn_max_age=600    )}

...
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',    ... #new
]

```

in the section where static files are configured,make the following modifications

_settings.py_
```python
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0.6/howto/static-files/

# This setting tells Django at which URL static files are going to be served to the user.
# Here, they will be accessible at your-domain.onrender.com/static/...
STATIC_URL = '/static/'
# Following settings only make sense in production and may break development environments.
if not DEBUG:    # Tell Django to copy statics to the `static files` directory
    # in your application directory on Render.
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    # Turn on the 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'
```

push the project to any online version control(GitHub/GitLab)


## Step 3 Deploying To Render
**Render database and web service setup**
go to your render dashboard and click on new Postgresql

![db](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kofuqg5jrnyljpahiqr9.png)

put in details for your new database and after that copy the internal database url 

Go to your render dashboard and click on new web service, and connect the repository you want to deploy(be sure to give render permission to access it),after that, you'll be asked to put in configuration details for your app


![1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wza9h9v6m7rvpkvldgf5.png)
put in a unique name for your service 

![2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vmpjugg4454wbogtashc.png)
Set the build command to

`./build.sh`

and the start command to

`gunicorn <your-project-directory>.wsgi:application`


![3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ye4mmsmpjsblan09gpme.png)
Under Advanced set the following Environment variables

`DATABASE_URL : The internal database URL for the database you created above`

`SECRET_KEY : Click Generate to get a secure random value`

`PYTHON_VERSION : the python version of your project eg 3.10.6`

`WEB_CONCURRENCY : 4`

That's it, click Create web service for your application to be deployed on render, after the build finishes your app would be available at <your service name>.onrender.com