Modern Django
Modern Django
Introduction
This will be a multi part tutorial series on how to create a "Modern" web application or SPA
using Django and React.js.
We will create a Note taking Single Page Application which will be rendered by ReactJS with
Django as an API backend. Let's call it "ponynote", because ponies are quite popular within
django community.
We will be using multiple libraries in this project, mainly, django-rest-framework for creating
APIs easily, react-router-dom for handling in-app routing, redux for maintaing global
application state.
This part of the series is about setting up your project to serve django and react seamlessly.
The code for this repository is hosted on my github, v1k45/ponynote. You can checkout part-1
branch to all the changes done till the end of this part.
Environment setup
I'll assume that you can setup your machine to run Python3 and Node >=6 on your own or using
the tutorials available on the internet.
I highly recommened you to use python virualenv so that your project dependencies do not
disturb system-wide python installation. I use virtualenvwrapper to maintain multiple virtualenvs
at single place using easy commands. I'll be using it throughout the tutorial.
Setup Django
After you have created and activated your virtualenv. You can start by installing django.
After installing django, we will create a project called ponynote using django-admin tool.
(ponynote) $ tree
.
└── ponynote
├── manage.py
└── ponynote
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
2 directories, 5 files
After migrating and runing development server, you will be able to see the "It worked!" welcome
page of Django on http://127.0.0.1:8000.
(ponynote) $ cd ponynote
(ponynote) $ ./manage.py migrate
(ponynote) $ ./manage.py runserver
Now that we have got django working, it is time to set it up to work with React JS.
If you haven't heard of Webpack before, it has now become the defacto tool to for module
bundling, compiling all your dependencies to small bundles (mostly one). You can learn more
about webpack from their official website.
We won't be directly writing webpack configuration ourselves though, we will use create-
react-app to generate the project boilerplate with all the configurations in it. Think of create-
react-app as django-admin startproject command but much more powerful.
For this, first we will install create-react-app sytem-wide using npm. Because we are
installing system-wide, we will need superuser permissions.
After installing we will create a react application using that command and then ejecting the
config files so that we can edit them ourselves.
$ create-react-app frontend
$ cd frontend
$ npm run eject
$ tree -I node_modules
.
├── config
│ ├── env.js
│ ├── jest
│ │ ├── cssTransform.js
│ │ └── fileTransform.js
│ ├── paths.js
│ ├── polyfills.js
│ ├── webpack.config.dev.js
│ ├── webpack.config.prod.js
│ └── webpackDevServer.config.js
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── README.md
├── scripts
│ ├── build.js
│ ├── start.js
│ └── test.js
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
└── registerServiceWorker.js
5 directories, 23 files
It is pretty obvious by the directory name which files are stored where.
Now that we have a working django server and webpack dev server running react, we will now
integrate both of them so that Django can show the SPA from it's own server. We will do that
using django-webpack-loader a django application which injects link and script tag for the
bundles which webpack generates dynamically.
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.dev.json'),
}
}
To serve the index page of the application we need to create a view and template in django. We'll
start by creating an index template at templates/index.html in project root. We will also need
to update the project's template settings so it can detect the template directory.
TEMPLATES = [
{
# ... other settings
'DIRS': [os.path.join(BASE_DIR, "templates"), ],
# ... other settings
},
]
The HTML division with root id is the mounting point of our react application. The
render_bundle tag with main as argument renders script tag for bundle named main which is
produced by our webpack config.
Now that the template is ready, let's create a view to serve it. Since this will be a plain template,
we can use django's TemplateView directly in our url config. In your project ponynote.urls.py
file:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', TemplateView.as_view(template_name="index.html")),
]
If you refresh your django homepage, you should see an error page with text Are you sure
webpack has generated the file and the path is correct?. This means
webpack_loader was searching for a file we specified in settings and was unable to find it.
In order to generate this file, we need to install webpack-bundle-tracker plugin and configure
webpack to generate required files. In frontend directory, run the following commands:
In your frontend/config/paths.js add the following key and value in the module.exports
object.
module.exports = {
// ... other values
statsRoot: resolveApp('../'),
}
module.exports = {
entry: [
// ... KEEP OTHER VALUES
// this will be found near line 30 of the file
require.resolve('webpack-dev-server/client') + '?http://localhost:3000',
require.resolve('webpack/hot/dev-server'),
// require.resolve('react-dev-utils/webpackHotDevClient'),
],
plugins: [
// this will be found near line 215-220 of the file.
// ... other plugins
new BundleTracker({path: paths.statsRoot, filename: 'webpack-
stats.dev.json'}),
],
}
Put headers object in the object returned by the exported function. This object is to be placed at
the same level of https and host properties.
headers: {
'Access-Control-Allow-Origin': '*'
},
That's it. Stop the webpack server and run it again and go to http://localhost:8000/, you should
see the same react welcome page as you did on webpack server page.
Now, any changes you do in src/App.js file will be instantly reflected on the opened page in
browser using hot loading.
Since this is a multi-part tutorial series, it might take some time until we reach part 4/5 where I
intend to talk about deployment. I'm writing the webpack deployment guide here for people who
don't want to wait until part 4 or they know react and they just need a deployable django +
webpack setup.
The production setup is pretty similar to changes we did for development setup. We will edit
some config values in the webpack.config file.
Start with creating a ponynote/production_settings.py file at the same level of your project
settings.py. For this project, the production server will use this settings file:
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "assets"),
]
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.prod.json'),
}
}
The above config tells django to look for static files in assets directory of project root and use
webpack-stats.prod.json as webpack stats file.
After this, create a directory assets/bundles/ in your project root. This directory will store all
our static assets. The bundles sub-directory will be used as build target. Webpack will save all
the build file to assets/bundles.
$ mkdir -p assets/bundles
module.exports = {
// KEEP OTHER VALUES
output: {
// NEAR LINE 67
Here we configured webpack to set static/bundles/ as publicPath because the build files
will be stored in assets/bundles and /static/ url points to the assets directory. We also
remove static prefixes from filenames and path to prevent unnecessary nesting of build files.
This will make webpack move the whole files directory into assets/bundles without creating
an additional static directory inside it.
After saving the file, we can build the javascript files using the following command:
To check if everything was setup properly, we can run django server using production settings
with webpack server stopped.
If you check http://localhost:8000/, you'll see the same page which was rendered when webpack
server was running. If you check the source code of the webpage, you'll see the js files are now
being served directly through django and not webpack.
Important points
It is better to build your js files on your CI server or your deployment server instead of
including them in version control or source code.
Make sure you run collectstatic after you build the js files, otherwise your
webserver won't be able to find the build files.
Make sure your build generates a webpack-stats.prod.json file. If you are deploying
by building the files manually, make sure you also include it when you're copying files
from your machine to server.
All the directory and filenames specified above are not enforced in any sense. Feel free to change
the directory location or filenames to your liking. But make sure all config files are properly
updated.
That's all on how to setup react and django to work together. In the next post we'll setup in-
application routing using react-router-dom and global state management using redux.
References