Simon (Sai)
Posted on January 15, 2023
⚠️ This guide is for versions of Inertiajs before v 1.0. I will be including the upgrade to InertiaJs V 1.0 in Part 2.
Motivations: I prepared this guide to solve a problem I was having with one of the projects that I have in production. I won't bore you with the details but, what I can say about it is that it's a Django project that makes use of ReactJs using Webpack but in a kind of thrown together way that made development a pain. With that in mind, I decided to search for a better way. Hopefully this will be of help to someone.
I'll be splitting this guide into two parts just to make it easier to consume.
Prerequisites
- Some experience with the Django framework and React
- Have an environment that is ready for Django app development (the usual requirements like Pip / Pipenv and so on)
- Python 3.7+
- NodeJS 16.x+
- React Dev Tools
Tested platforms
- ✅
Ubuntu 22.04 LTS
- ✅
MacOS
- ✅
Windows
** Thanks to @TappMax for testing
What we'll be doing in Part. 1
- Setting up our Django project
- Setting up GIT (optional, but usually a good idea)
- Installing the required Django dependencies and configuring them
- Setting up our Inertia App
- Testing Django with our InertiaJS App
Initial Setup of up our Django Project
For this guide, we will be building a simple contact list manager. Since the main focus is to walk through getting Django, InertiaJS, React with Vite to play nicely, we will be skipping things like Authentication and styling (for the most part).
Let's begin getting our Django project started
- Let's create a folder for our project and navigate to it
mkdir contact-app
cd contact-app
- Create your virtual environment using the following command (or your preferred way to create a virtual environment):
python3 -m venv .venv
- activate your newly created environment using:
source .venv/bin/activate
- install Django 4.1 LTS using the command and it would be a good idea to upgrade pip in our virtual environment as well
pip install Django==4.1
pip install --upgrade pip
ℹ️ Your terminal output might be different but as long as all the packages were installed properly, you can proceed to the next step
⚠️ A note about the settings file in the django project that was just created: the SECRET_KEY
is something that should be kept safe. There are a few things that we can do to secure our settings file but we'll save that for another time.
- Create our django project in our current directory
django-admin startproject contact_manager .
ℹ️ If the command ran correctly, you will not see anything returned. You can always checking using the ls command
- Let's make sure our application is working correctly
./manage.py runserver
ℹ️ Your terminal should show something similar. Don't worry about unapplied migrations warning. We'll fix those soon.
At this point, you should be able to navigate to the development server address.
We should be up and running at this point. The console will tell us that we have unapplied migrations...that's ok for now
ℹ️ We should see the start page when we navigate to http://127.0.0.1:8000 as directed in the terminal output
# All the commands
python3 -m venv .venv
source .venv/bin/activate
pip install Django==4.1
pip install --upgrade pip
./manage.py runserver
# Windows Notes: Provided by Max
# All the commands on windows
python -m venv .venv
.venv\Scripts\activate
pip install Django==4.1
pip install --upgrade pip
manage.py runserver
Setting up git (optional, but recommended)
This step is optional but recommended. If you have the development server run, go ahead and stop it.
⚠️ if you intend to follow this step, the assumption here is that you have experience setting up GIT. That said, if you don't, I gotchu. This link will help: https://www.atlassian.com/git/tutorials/install-git
- Let's initialize our git repo for this project
git init
- You should see something that looks like
Initialized empty Git repository in PATH/TO/YOUR/PROJECT
- Let's get a git ignore file in place from now. Depending on your IDE or Editor, you may be able to generate a
.gitignore
file. - Create a file named
.gitignore
in the root of the project and copy and paste the following (this file is probably overkill for our purposes)
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# PyInstaller
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Minimal Django:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Minimal Virtualenv
.venv
# Jetbrains
.idea
# Minimal NodeJS
dist
node_modules
- With this in place, we can add all our files and then commit them
git add .
git commit -m 'initial commit'
Installing Django Dependencies
In this section, we'll be installing inertia/django and django-vite and configuring our settings to make things work.
- If you're using version control, let's go ahead and make a new branch from main
git checkout -b install-dependencies # or whatever you want to call it
Installing Inertia/Django
For more information about the Inertia.js Django Adapter: https://pypi.org/project/inertia-django/
pip install inertia-django
ℹ️ Your output should look something like what's shown above
Now would be a good time to open up the project in your IDE or editor. I'll be using Pycharm Professional but VSCode is fine too. And let's have a look at the project structure so far.
- Next, we will update our
INSTALLED_APPS
in oursettings.py
file to inertiainertia
INSTALLED_APPS = [
# django inertia apps,
'inertia',
# our project's apps,
]
- and then update our
MIDDLEWARE
insettings.py
to include the inertia middlewareinertia.middleware.InertiaMiddleware
MIDDLEWARE = [
# django middleware,
'inertia.middleware.InertiaMiddleware',
# your project's middleware,
]
ℹ️ Your settings.py
should look something like the image above
Next, create a template file templates/base.html
having the initial structure
<!DOCTYPE *html*>
<html *lang*="en">
<head>
<meta *charset*="UTF-8">
<title>Title</title>
</head>
<body>
{% block *inertia* %}{% endblock %}
</body>
</html>
- To settings, add
INERTIA_LAYOUT = 'base.html'
to the end of the settings file
- Update
DIRS
inTEMPLATES
to includeBASE_DIR / 'templates'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # add this line
'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',
],
},
},
]
ℹ️ The TEMPLATES
section of your settings.py
should look like this
Installing Django-Vite
pip install django-vite
- Once installed, add
django-vite
to our installed apps
INSTALLED_APPS = [
# django apps,
'django_vite',
'inertia',
# your project's apps,
]
- In the root of the project, we will need to create a
package.json
file by usingnpm
npm init -y
- Now we can install
Vite
🚀
npm i -D vite
- For vite to work, we need to create a
vite.config.js
file in the root of our project with the following content
import { resolve } from 'path';
module.exports = {
plugins: [],
root: resolve('./react-app'),
base: '/static/',
server: {
host: 'localhost',
port: 3000,
open: false,
watch: {
usePolling: true,
disableGlobbing: false,
},
},
resolve: {
extensions: ['.js', '.json'],
},
build: {
outDir: resolve('./react-app/dist'),
assetsDir: '',
manifest: true,
emptyOutDir: true,
target: 'es2015',
rollupOptions: {
input: {
main: resolve('./react-app/src/main.js'),
},
output: {
chunkFileNames: undefined,
},
},
},
};
- Update the file
templates/base.html
with the following content
{% load django_vite %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- include vite hmr -->
{% vite_hmr_client %}
{% vite_asset 'src/main.js' %}
<title>Title</title>
</head>
<body>
{% block inertia %}{% endblock %}
</body>
</html>
ℹ️ we are referencing js/main.js
, we will create this file eventually.
- Update
settings.py
to include the necessary settings for Django Vite
# InertiaJS Related settings
INERTIA_LAYOUT = 'base.html'
# We need this for django form posting
CSRF_HEADER_NAME = 'HTTP_X_XSRF_TOKEN'
CSRF_COOKIE_NAME = 'XSRF-TOKEN'
# Where ViteJS assets are built.
DJANGO_VITE_ASSETS_PATH = BASE_DIR / "react-app" / "dist"
# If we should use HMR or not.
DJANGO_VITE_DEV_MODE = DEBUG
# we need this to get around cors issues
DJANGO_VITE_DEV_SERVER_HOST = '127.0.0.1'
# this is the default, but I'm leaving this here, so you know what to change if you want to run on a different port
DJANGO_VITE_PORT = 3000
# Name of our static files' folder (after called python manage.py collectstatic)
STATIC_ROOT = BASE_DIR / "static"
# Include DJANGO_VITE_ASSETS_PATH into STATICFILES_DIRS to be copied inside
# when run command python manage.py collectstatic
STATICFILES_DIRS = [DJANGO_VITE_ASSETS_PATH]
- Let's create our
react-app/dist
folder which we will use eventually (Django's dev server will complain about it) - Let's create our entry point for what will become our React/InertiaJS app
react-app/src/main.js
alert('Django Vite says hello world!');
- Update
package.json
to includedev
andbuild
scripts so that we can run vite
{
"scripts": {
"build": "vite build",
"dev": "vite",
"test": "echo \"Error: no test specified\" && exit 1"
},
}
- At this point, we should be able to run
vite
and we shouldn't see any errors in the terminal. That said, we still can't do anything useful yet
In our browser, we should able to access our js file
- Let's add a file for our views and we'll call it...
contact_manager/views.py
😏
from django.shortcuts import render
def index(request):
return render(request, "base.html")
- Let's update our urls
urls.py
from django.contrib import admin
from django.urls import path
# this was added
from contact_manager import views
# from contact_manager.views import index # this is a valid import as well
urlpatterns = [
path('', views.index), # this was added
path('admin/', admin.site.urls),
]
- Open a new terminal and run the django dev server
- Navigate to
http://127.0.0.1:8000
and we should see our JavaScript alert.
ℹ️ We have HMR working. Of course you can check that it works by changing the main.js
file and observing what happens. 👍
- Since we're at a decent point, let's commit our changes before we move forward (if you're using version control)
git add .
git commit -m "Install dependencies and did initial setup for vite to serve main.js file via vite"
Now for the interesting part 🙌
Update the previously created contact_manager/views.py
fileto include an import from inertia
from inertia import inertia
@inertia('Home/Index')
def index(request):
return {
'contacts': ['Acid Burn', 'Crash Override', 'Lord Nikon'],
}
ℹ️ The object we return from our index
function becomes the props of the React
component we will eventually render
If everything worked correctly, when we inspect our index page, we should see a div
that has id="app"
along with a data-page
attribute that contains the contacts
as defined in our python view file.
The last thing we'll do for Part 1 of this tutorial is to setup our InertiaJS application
- Let's install the dependencies we need via NPM
npm i -D react react-dom @vitejs/plugin-react
Edit: For our InertiaJs dependencies @inertiajs/inertia-react @inertiajs/progress, we will need specific versions as shown in the package.json
snippet below.
"devDependencies": {
"@inertiajs/inertia-react": "^0.8.1",
"@inertiajs/progress": "^0.2.7",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@vitejs/plugin-react": "^3.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"vite": "^4.0.4"
}
Stop vite if you have not yet done so
Rename our
main.js
tomain.jsx
and replace the content with what is shown below
import React from 'react';
import { createRoot } from 'react-dom/client';
import { createInertiaApp } from '@inertiajs/inertia-react';
import { InertiaProgress } from '@inertiajs/progress';
import Layout from './components/Layout.jsx';
const pages = import.meta.glob('./pages/**/*.jsx');
document.addEventListener('DOMContentLoaded', () => {
InertiaProgress.init();
createInertiaApp({
resolve: async (name) => {
const page = (await pages[`./pages/${name}.jsx`]()).default;
page.layout = page.layout || Layout;
return page;
},
setup({ el, App, props }) {
createRoot(el).render(<App {...props} />);
},
}).then();
});
- Let's update our
vite.config.js
file to work with our changes
import { resolve } from 'path';
import react from '@vitejs/plugin-react';
module.exports = {
plugins: [
react({
include: '**/*.disabled',
}),
],
root: resolve('./react-app'),
base: '/static/',
server: {
host: 'localhost',
port: 3000,
open: false,
watch: {
usePolling: true,
disableGlobbing: false,
},
},
resolve: {
extensions: ['.js', '.json'],
},
build: {
outDir: resolve('./react-app/dist'),
assetsDir: '',
manifest: true,
emptyOutDir: true,
target: 'es2015',
rollupOptions: {
input: {
main: resolve('./react-app/src/main.jsx'),
},
output: {
chunkFileNames: undefined,
},
},
},
};
- Let's create a layout component
src/components/Layout.jsx
which we will use to wrap ourpages
const Layout = ({ children }) => {
return (
<main>
<div>{children}</div>
</main>
);
};
export default (page) => <Layout>{page}</Layout>;
- Update
templates/base.html
to point to ourmain.jsx
file - Create our Index page component
src/pages/Home/Index.jsx
and paste the following content
export default function Home ({contacts}) {
return (
<div>
<h1>Contact List</h1>
{Array.isArray(contacts) && contacts.length ? <ul>
{contacts.map(contact => <li key={contact}>{contact}</li>)}
</ul> : <p>No contacts yet...</p>}
</div>
);
}
ℹ️ Now, if everything worked, we should see something that looks like the image below 👍
- Go ahead and commit our changes
git add .
git commit -m "update implementation to render inertia js app with props"
If you've made it this far and everything works then, nice! As you can see, InertiaJs is pretty cool and being able to use it with Django makes it way cooler (imo).
Coming up in part 2, we'll take a look at the following:
- Upgrade InertiaJs to v1.0
- Integrating TypeScript
- Installing Material UI (you can use any component library you want)
- Implementing the contact app
- Backend
- models, views
- Frontend
- Pages and components
Hope you found this guide useful. Let me know if you have questions or suggestions.
References:
The following links were used in the making of this guide
- inertia-django https://pypi.org/project/inertia-django/
- django-vite https://github.com/MrBin99/django-vite
-
vite.config.js
original source: https://raw.githubusercontent.com/MrBin99/django-vite-example/master/vite.config.js - InertiaJs + Django Setup video (inspiration for this guide) https://www.youtube.com/watch?v=85-i4fr5MeU
Posted on January 15, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.