The Python Geek

Setting Up React in A Django Project

Step by step process of setting up React

Setting Up React in A Django Project

Created: Fri 23 November 2018

Tags: React , Django , Python


Introduction

ReactJS is a library used for creating dynamic, rich user interfaces. Often times people compare Angular to React but what separates them is the fact that React if a library and Angular is a framework. React is a more lightweight solution with not as steep of a learning curve which makes it more ideal to use in a Django project. Here I am going to show how I had set up React in a Django project in order to create the COD app.

React is a powerful library because it allows us to break apps down into small components and provides mechanisms of tracking properties and application state. It provides a convenient syntax that is HTML-like, which we call JSX. What is most impressive is that it runs on the concept of the Virtual DOM. In essense what this means is that only certain parts of the DOM are updated or re-rendered if needed.

Installations

Below are base minimum JS installations required. Seek out documentation for the best way to install for your system.

Below are base minimum Python installations required. Both can be done using 'pip install'.

Start a Project

At the console, let's create a django project and change directory into the project

C:\> django-admin startproject myproject
C:\> cd myproject
C:\myproject>

Install Node Packages

Next we want to install node packages necessary for us to create a React application. To do this we need to define a file call package.json. This json file will contain a list of dependencies and the associated versions. This is essential to the project as it tracks dependencies and allows npm to easily interact with it to install or update packages.

In the root of the django project create a file called package.json with the below:

{
  "name": "App",
  "version": "1.0.0",
  "main": "app.js",
  "author": "bvmcode",
  "license": "MIT",
  "scripts": {
    "build": "C:/myproject/node_modules/.bin/webpack --config webpack.config.js"
  },
  "dependencies": {
    "babel-cli": "^6.26.0",
    "babel-loader": "^7.1.1",
    "babel-preset-env": "1.5.2",
    "babel-preset-react": "6.24.1",
    "react": "^16.0.0",
    "react-dom": "^16.0.0",
    "webpack": "^3.1.0",
    "webpack-bundle-tracker": "0.0.93"
  }
}

Now we need to install these packages which we can simply do with npm. When its done, you'll notice that we will have a node_modules directory in the root of the project containing all of these packages.

C:\myproject> npm install

Defining Node Packages

First, let's define what babel is. At a high level, babel transpiles ES6 JS code into code that browsers can understand. Why is this important? This allows developers to use cutting-edge javascript on the backend and have it transpile correctly for the frontend. Webpack will use babel for transpiliing and in addition it will handle necessary bundling of code and assets.

Django Configuration

Firstly let's create some directories in the root of the project that we will end up needing.

Now let's hop into our myproject/settings.py file to update some important configuration details.

First we need to make sure we are adding the django-webpack-loader into our apps. Now we haven't really defined what this python package does yet. In essence this will give us the ability in django to reference webpack generated files into our django templates.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'webpack_loader'
]

Let's add the django webpack loader configuration. In essence, this states that it will drop the necessary bundled files indo the bundles directory which is in the static directory. This will also generate a webpack-stats.json file in the root of the project.

WEBPACK_LOADER = {
    'DEFAULT':{
        'CACHE': not DEBUG,
        'BUNDLE_DIR_NAME': 'bundles/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
    }
}

Let's update where django will look for templates, which we want to be in the templates directory off of the root of the project.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        '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',
            ],
        },
    },
]

Lastly, let's update where the project looks for static files, which is in the static folder off of the root of the project.

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]

Webpack Configuration

We now need to add a couple more files into the root of our project. First, let's create our webpack.config.js file. The entry key defines the entry point of our react app. Here it is defines as /react/App.js. So when webpack runs, it will look for the react directory off of our root and then look for the App.js file. The output key defines where the transpiled code will live and the name of the file. The plugin key defines the bundle tracker which writes to webpack.stats.json. This file should sound familiar from the django configuration. Django reads the json file so that it can determine which bundles is connected to which app. Finally, in rules we add the babel-loader and let it know it can work to transpile all JS files except for those in node_modules.

const path = require('path');
const BundleTracker = require('webpack-bundle-tracker');

module.exports = {
    entry:{
        App:'./react/App.js'
    },
    output:{
        path:path.join(__dirname, 'static/bundles'),
        filename: '[name].js'
    },
    plugins:[new BundleTracker({filename: './webpack-stats.json'})],
    module:{
        rules:[
            {
                loader: 'babel-loader',
                test: /\.js$/,
                exclude: /node_modules/
            }
        ]
    }
};

Let us now create the .babelrc file in the root of the project. This is a babel configuration file telling babel to use the env and react presets in the transpiling.

{
  "presets": ["env", "react"]
}

Sample App Time!

Let's create a sample application where we can change the color of a box randomly by clicking a button. Let's create an App.js file in the root of the react directory. Let's also create a components directory in the react directory. App.js will be the entry point and the components will be all separate pieces of the application.

Let's define the first component, the button. Let's call the file Button.js. We reference the property handleOnClick. We will see how this is created and passed in the App.js file. So Button.js will create a Button element to use in App.js.

import React from 'react'


export default class Button extends React.Component {
      constructor(props) {
        super(props);
    }


    render(){
          return(
              <div>
                    <button onClick={this.props.handleClick}>Change Color</button>
             </div>
          )
    }

}

Now let's create the Box component in Box.js. Here is where the box color will change based off the button click. Notice we pass in a color prop into the styling.

import React from 'react'


export default class Box extends React.Component {
      constructor(props) {
        super(props);
    }


    render(){
          const boxStyle = {
              height:'200px',
              width:'200px',
              backgroundColor:this.props.color
        };
          return(
              <div style={boxStyle}>
                  
             </div>
          )
    }

}

Now, let's write out the application in App.js using these two elements. Here is where the App will be brought to life using the components we wrote and the render method of ReactDOM. We see that we write out the handleChange method to randomly select a color. This updates the state that we defined in the constructor, which we default to color of black. The state here is important, its what drives the changes in the application. When the states changes the application knows to re-render the correct parts of the DOM according to the actions taken (button click). We see that in the Box element we pass in the state. In the Button element we pass in the handleChange method. Both of these are received as properties in those elements as we saw earlier.

import React from 'react';
import ReactDOM from 'react-dom';
import Box from './components/Box';
import Button from './components/Button';

export default class App extends React.Component {
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.state = {color:'#000000'}
    }

    handleClick(e) {
          e.preventDefault();
          const colors = ['#80d4ff', '#4d4dff', '#4dff4d', '#ff4d94', '#ffd11a'];
          const color = colors[Math.floor(Math.random()*colors.length)];
          this.setState({color:color});
    }

    render(){
          return(
              <div>
                  <h1>Random Box Color App</h1>
                    <Box color={this.state.color}/>
                    <Button handleClick={this.handleClick}/>
             </div>
          )
    }

}

ReactDOM.render(<App/>, document.getElementById('react'))

So remember that build script that we had in the package.json file? Now we can use it. What it will do is use babel to transpile and webpack will take the code and associated assets and reduce it to App.js in static/bundles. All this driven through the configuration in webpack.config.js.

C:\myproject> npm run build

Assuming we get no errors, we can go ahead set up three pieces in the django project - view, url and template. Let's start with the most interesting one, the template.

Let's throw index.html into the templates directory we created earlier. The template tag at the top loads the django-webpack-loader. This will look into the webpack-stats.json file. The render_bundle template tag states that it wants to load App. When webpack-stats.json confirms its existence and where its located and the app is loaded accordingly via static/bundles/App.js file. The div with an id of react corresponds with the id defined in ReactDOM.render in the react/App.js file. So if all this works out, template will allow us to render the app.

{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="react"></div>
    {% render_bundle 'App' %}
</body>
</html>

Let's set up the views.py file in myproject (same directory as settings.py). We have to create the file. We just want to have a view that points to the template.

from django.shortcuts import render

def index(request):
    return render(request, 'index.html')

And now we want to set up our urls.py file in the myproject directory. This will point to the view so that when we pull up the root url in the browser we can load the app.

from django.contrib import admin
from django.urls import path
from .views import index

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', index)
]

Now, we are good to go. Let's run the server and see if it works.

C:\myproject> python manage.py runserver

In the browser, we see that we can click the button to randomly change the box color. All this is done without refreshing the page. This application is fully loaded into the browser.

App loaded

App Loaded

Button click

App Loaded

Button click

App Loaded

Conclusion

I hope this blog entry helped you set up react in a django project while also helping with some introductory language. Please feel free to comment thoughts or corrections.