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
- Heroku CLI installed in your machine
- Yarn installed in your path
- Django react project Blisting, what was I create the last article. Download here
Setting up Django for deployment
Install some package/dependencies for deployment
$ pip install whitenoise gunicorn dj-database-url psycopg2-binary
ALLOW_HOSTS and make false
Edit blisting/blisting/settings.py file
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
MIDDLEWARE = [ # 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # ... ]
Settings up the static file in blisting/settings.py
# 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
$ 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
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.
python-3.8.3
Check python runtime
$ python -v
Declare Procfile
create blisting/Procfile in the project root directory
release: python manage.py migrate web: gunicorn blisting.wsgi
Generate requirements.txt file
$ pip freeze > requirements.txt
how does the project structure look like?
. ├── 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
"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”
$ touch package.json
configure blisting/package.json file. “engines” configurations may be different for your app. So config with your node and npm version.
{ "name": "Blisting", "version": "1.0.1", "description": "Business listing application", "main": "index.js", "repository": "[email protected]:sajalmia381/django-react-setup.git", "author": "Md Sajal Mia <[email protected]>", "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.
$ 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”
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
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.
- login with terminal
$ heroku login
- Create heroku apps
$ heroku apps:create -a blisting
- Add buildpack in Heroku, learn more about Heroku buildpack
$ 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.
- Add Postgres database in Heroku app
$ 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
- Disable collectstatic file
$ heroku config:set DISABLE_COLLECTSTATIC=1
- You can check configuration
$ heroku config
- So finally push to Heroku
$ git push heroku master
- Build react application and make usable for Django
$ python manage.py collectstatic
conclusion