Tech Incent
DjangoReact

How to deploy django and react in heroku ?

how-to-deploy-django-and-react-in-heroku

There are lots of hosts for setting up Django API and React. but most of them are very complicated processes but there are main two different methodologies:

  • Separate Django back-end and react front-end: In this method, Django and React will be deployed separately. Django server instance will run Django, on other hand, React server instance handle react app. but there are communicate data with API. it’s important to set up a “Cross-Origin Resource Sharing(CORS)” configuration. Most developer development with Django React application with this separate method.
  • Serve with the same host: it’s the best way to deploy small and medium django react applications. you don’t want to spend a good of cost for a small application like a blog, portfolio, business profile, etc.

In this article, we deploy Django and React application (what was created in last article) in the Heroku server. We will serve Django React apps with the same host

Before we go process we need to set up Django and react together, So check the django and react setup

Requirements for deployment

Setting up Django for deployment

Install some package/dependencies for deployment

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ pip install whitenoise gunicorn dj-database-url psycopg2-binary
$ pip install whitenoise gunicorn dj-database-url psycopg2-binary
$ pip install whitenoise gunicorn dj-database-url psycopg2-binary

ALLOW_HOSTS and make false

Edit blisting/blisting/settings.py file

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DEBUG = False
ALLOWED_HOSTS = ['.yourappname.herokuapp.com']
DEBUG = False ALLOWED_HOSTS = ['.yourappname.herokuapp.com']
DEBUG = False
ALLOWED_HOSTS = ['.yourappname.herokuapp.com']

Static Files configuration

Most of developer recommend django static files to store in AWS S3. Learn more how to store django static file with AWS S3. But for this tutorial, we serve static files in the same host. keep it in mind. AWS S3 best for serving static files.

Configure whitenoise middleware in blisting/settings.py

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
MIDDLEWARE = [
# 'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
# ...
]
MIDDLEWARE = [ # 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # ... ]
MIDDLEWARE = [
  # 'django.middleware.security.SecurityMiddleware',
  'whitenoise.middleware.WhiteNoiseMiddleware',
  # ...
]

Settings up the static file in blisting/settings.py

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# https://docs.djangoproject.com/en/3.0/howto/static-files/
REACT_APP_PATH = os.path.join(BASE_DIR, 'frontend')
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [
os.path.join(REACT_APP_PATH, 'static')
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# https://docs.djangoproject.com/en/3.0/howto/static-files/ REACT_APP_PATH = os.path.join(BASE_DIR, 'frontend') STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static') STATICFILES_DIRS = [ os.path.join(REACT_APP_PATH, 'static') ] STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# https://docs.djangoproject.com/en/3.0/howto/static-files/
REACT_APP_PATH = os.path.join(BASE_DIR, 'frontend')

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

STATICFILES_DIRS = [
    os.path.join(REACT_APP_PATH, 'static')
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

make a static directory in the project root directory or blisitng/static

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ mkdir static
$ mkdir static
$ mkdir static

Add database config in settings.py for heroku app

add database settings in django “blisting/settings.py” file. make sure DATABASE config is top of this

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
import dj_database_url
db_from_env = dj_database_url.config()
DATABASES['default'].update(db_from_env)
DATABASES['default']['CONN_MAX_AGE'] = 500
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } import dj_database_url db_from_env = dj_database_url.config() DATABASES['default'].update(db_from_env) DATABASES['default']['CONN_MAX_AGE'] = 500
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
import dj_database_url
db_from_env = dj_database_url.config()
DATABASES['default'].update(db_from_env)
DATABASES['default']['CONN_MAX_AGE'] = 500

Declare runtime for Django

Create a “blisting/runtime.txt” file, I am using python-3.8.3 your case may be different. make sure you declare the right version of yours.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
python-3.8.3
python-3.8.3
python-3.8.3

Check python runtime

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ python -v
$ python -v
$ python -v

Declare Procfile

create blisting/Procfile in the project root directory

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
release: python manage.py migrate
web: gunicorn blisting.wsgi
release: python manage.py migrate web: gunicorn blisting.wsgi
release: python manage.py migrate
web: gunicorn blisting.wsgi

Generate requirements.txt file

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ pip freeze > requirements.txt
$ pip freeze > requirements.txt
$ pip freeze > requirements.txt

how does the project structure look like?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
.
├── blisting
│ ├── asgi.py
│ ├── __init__.py
│ ├── __pycache__
│ ├── settings.py
│ ├── urls.py
│ ├── views.py
│ └── wsgi.py
├── db.sqlite3
├── frontend
│ ├── node_modules
│ ├── package.json
│ ├── Procfile
│ ├── public
│ ├── README.md
│ ├── src
│ └── yarn.lock
├── list
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ ├── models.py
│ ├── __pycache__
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── manage.py
├── Procfile
├── README.md
├── requirements.txt
├── runtime.txt
├── static
│ ├── admin
│ ├── css
│ ├── js
│ └── rest_framework
├── venv
│ ├── bin
│ ├── include
│ ├── lib
│ └── share
. ├── blisting │ ├── asgi.py │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ ├── views.py │ └── wsgi.py ├── db.sqlite3 ├── frontend │ ├── node_modules │ ├── package.json │ ├── Procfile │ ├── public │ ├── README.md │ ├── src │ └── yarn.lock ├── list │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ ├── models.py │ ├── __pycache__ │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── manage.py ├── Procfile ├── README.md ├── requirements.txt ├── runtime.txt ├── static │ ├── admin │ ├── css │ ├── js │ └── rest_framework ├── venv │ ├── bin │ ├── include │ ├── lib │ └── share
.
├── blisting
│   ├── asgi.py
│   ├── __init__.py
│   ├── __pycache__
│   ├── settings.py
│   ├── urls.py
│   ├── views.py
│   └── wsgi.py
├── db.sqlite3
├── frontend
│   ├── node_modules
│   ├── package.json
│   ├── Procfile
│   ├── public
│   ├── README.md
│   ├── src
│   └── yarn.lock
├── list
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   ├── models.py
│   ├── __pycache__
│   ├── serializers.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── manage.py
├── Procfile
├── README.md
├── requirements.txt
├── runtime.txt
├── static
│   ├── admin
│   ├── css
│   ├── js
│   └── rest_framework
├── venv
│   ├── bin
│   ├── include
│   ├── lib
│   └── share

Set up React app

Add proxy in main react blisting/frontend/package.json file

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"proxy": "http://localhost:8000"
"proxy": "http://localhost:8000"
"proxy": "http://localhost:8000"

Serve React in Heroku app

Our project root directory is “blasting”. and you know the React root path is “blisting/frontend” directory. Now the problem is Heroku doesn’t detect frontend react apps. Heroku requires apps will define in the root directory. So How can make we detect react to heroku app?

Method one, we can cut all files and folder and paste in root directory “blasting”, it may some more problem with conflict with django application.

Method Two, On the other and best way, we used it. So follow this direction,
Make a package.json file in root directory “blisting/package.json”

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ touch package.json
$ touch package.json
$ touch package.json

configure blisting/package.json file. “engines” configurations may be different for your app. So config with your node and npm version.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"name": "Blisting",
"version": "1.0.1",
"description": "Business listing application",
"main": "index.js",
"repository": "git@github.com:sajalmia381/django-react-setup.git",
"author": "Md Sajal Mia <sajalmia381@gmail.com>",
"license": "MIT",
"private": true,
"scripts": {
"heroku-prebuild": "NODE_ENV=production cd frontend/ && yarn install && yarn build && cd .."
},
"cacheDirectories": [
"frontend/node_modules"
],
"engines": {
"node": "10.20.1",
"npm": "6.14.5"
}
}
{ "name": "Blisting", "version": "1.0.1", "description": "Business listing application", "main": "index.js", "repository": "git@github.com:sajalmia381/django-react-setup.git", "author": "Md Sajal Mia <sajalmia381@gmail.com>", "license": "MIT", "private": true, "scripts": { "heroku-prebuild": "NODE_ENV=production cd frontend/ && yarn install && yarn build && cd .." }, "cacheDirectories": [ "frontend/node_modules" ], "engines": { "node": "10.20.1", "npm": "6.14.5" } }
{
  "name": "Blisting",
  "version": "1.0.1",
  "description": "Business listing application",
  "main": "index.js",
  "repository": "git@github.com:sajalmia381/django-react-setup.git",
  "author": "Md Sajal Mia <sajalmia381@gmail.com>",
  "license": "MIT",
  "private": true,
  "scripts": {
    "heroku-prebuild": "NODE_ENV=production cd frontend/ && yarn install && yarn build && cd .."
  },
  "cacheDirectories": [
    "frontend/node_modules"
  ],
  "engines": {
    "node": "10.20.1",
    "npm": "6.14.5"

  }
}

Make yarn.lock file in the root directory “blisting/yarn.lock”, and leave it blank. heroku automatic install yarn and server all module in this file.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ touch yarn.lock
$ touch yarn.lock
$ touch yarn.lock

Serve react view instant by Django

create django dynamic view that will serve all react views. I am talking about the real project, where are you create this view? Example: creating a “python manage.py startapp core” or create a views.py file in the main root directory blisting/blisting/views.py where it is all core configuration store. in this case, we will create in “blisting/blisting/views.py”

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import os
import logging
from django.http import HttpResponse
from django.views.generic import View
from django.conf import settings
class FrontendAppView(View):
"""
Serves the compiled frontend entry point (only works if you have run `yarn
build`).
"""
index_file_path = os.path.join(settings.REACT_APP_DIR, 'build', 'index.html')
def get(self, request):
try:
with open(self.index_file_path) as f:
return HttpResponse(f.read())
except FileNotFoundError:
logging.exception('Production build of app not found')
return HttpResponse(
"""
This URL is only used when you have built the production
version of the app. Visit http://localhost:3000/ instead after
running `yarn start` on the frontend/ directory
""",
status=501,
)
import os import logging from django.http import HttpResponse from django.views.generic import View from django.conf import settings class FrontendAppView(View): """ Serves the compiled frontend entry point (only works if you have run `yarn build`). """ index_file_path = os.path.join(settings.REACT_APP_DIR, 'build', 'index.html') def get(self, request): try: with open(self.index_file_path) as f: return HttpResponse(f.read()) except FileNotFoundError: logging.exception('Production build of app not found') return HttpResponse( """ This URL is only used when you have built the production version of the app. Visit http://localhost:3000/ instead after running `yarn start` on the frontend/ directory """, status=501, )
import os
import logging
from django.http import HttpResponse
from django.views.generic import View
from django.conf import settings


class FrontendAppView(View):
    """
    Serves the compiled frontend entry point (only works if you have run `yarn
    build`).
    """
    index_file_path = os.path.join(settings.REACT_APP_DIR, 'build', 'index.html')

    def get(self, request):
        try:
            with open(self.index_file_path) as f:
                return HttpResponse(f.read())
        except FileNotFoundError:
            logging.exception('Production build of app not found')
            return HttpResponse(
                """
                This URL is only used when you have built the production
                version of the app. Visit http://localhost:3000/ instead after
                running `yarn start` on the frontend/ directory
                """,
                status=501,
            )

Add frontend view function to blisting/blisting/urls.py

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from django.contrib import admin
from django.urls import path, include, re_path
from .views import FrontendAppView
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('list.urls')),
re_path(r'^', FrontendAppView.as_view()),
]
from django.contrib import admin from django.urls import path, include, re_path from .views import FrontendAppView urlpatterns = [ path('admin/', admin.site.urls), path('', include('list.urls')), re_path(r'^', FrontendAppView.as_view()), ]
from django.contrib import admin
from django.urls import path, include, re_path
from .views import FrontendAppView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('list.urls')),
    re_path(r'^', FrontendAppView.as_view()),
]

Set up Heroku server

I hope your machine has a Heroku CLI. and I also hope you have a Heroku account or you can create a Heroku account here.
I am configuration application with terminal instant Heroku CLI  but you can configure with Heroku dashboard.

  1. login with terminal
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ heroku login
    $ heroku login
    $ heroku login
  2. Create heroku apps
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ heroku apps:create -a blisting
    $ heroku apps:create -a blisting
    $ heroku apps:create -a blisting
  3. Add buildpack in Heroku, learn more about Heroku buildpack
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ heroku buildpacks:set heroku/python
    $ heroku buildpacks:add --index 1 heroku/nodejs
    Buildpack added. Next release on blisting will use:
    1. heroku/nodejs
    2. heroku/python
    Run git push heroku master to create a new release using these buildpacks.
    $ heroku buildpacks:set heroku/python $ heroku buildpacks:add --index 1 heroku/nodejs Buildpack added. Next release on blisting will use: 1. heroku/nodejs 2. heroku/python Run git push heroku master to create a new release using these buildpacks.
    $ heroku buildpacks:set heroku/python
    $ heroku buildpacks:add --index 1 heroku/nodejs
    Buildpack added. Next release on blisting will use:
      1. heroku/nodejs
      2. heroku/python
    Run git push heroku master to create a new release using these buildpacks.
  4. Add Postgres database in Heroku app
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ heroku addons:create heroku-postgresql:hobby-dev
    Creating heroku-postgresql:hobby-dev on ⬢ blisting... free
    Database has been created and is available
    ! This database is empty. If upgrading, you can transfer
    ! data from another database with pg:copy
    Created postgresql-shallow-41905 as DATABASE_URL
    Use heroku addons:docs heroku-postgresql to view documentation
    $ heroku addons:create heroku-postgresql:hobby-dev Creating heroku-postgresql:hobby-dev on ⬢ blisting... free Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pg:copy Created postgresql-shallow-41905 as DATABASE_URL Use heroku addons:docs heroku-postgresql to view documentation
    $ heroku addons:create heroku-postgresql:hobby-dev
    Creating heroku-postgresql:hobby-dev on ⬢ blisting... free
    Database has been created and is available
     ! This database is empty. If upgrading, you can transfer
     ! data from another database with pg:copy
    Created postgresql-shallow-41905 as DATABASE_URL
    Use heroku addons:docs heroku-postgresql to view documentation
  5. Disable collectstatic file
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ heroku config:set DISABLE_COLLECTSTATIC=1
    $ heroku config:set DISABLE_COLLECTSTATIC=1
    $ heroku config:set DISABLE_COLLECTSTATIC=1
  6. You can check configuration
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ heroku config
    $ heroku config
    $ heroku config
  7. So finally push to Heroku
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ git push heroku master
    $ git push heroku master
    $ git push heroku master

    buil-success

  8. Build react application and make usable for Django
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    $ python manage.py collectstatic
    $ python manage.py collectstatic
    $ python manage.py collectstatic

conclusion

 

Related posts

Django abstractuser with example

Sajal Mia

How to setup django static and media file in aws s3 ?

Sajal Mia

How to optimize your Django application for more speed with ORM?

Sajal Mia

How to add bootstrap in react?

Tech Incent

How to delete file when models instance is delete or update in Django?

Sajal Mia

How to work with django ajax requests ?

Sajal Mia