How the fuck do I set up Django, Django REST Framework, ReactJS and Browserify?

ReactJS (or simply "React") is killin' the front-end game right now. With its leveraging of virtual-dom and dedication to modularity and reusability, it's proving to be a beacon of hope to many developers on the bleeding edge of web technologies. Django, for similar reasons, remains a super powerful tool set. Therefore, I wanted to combine the two powers.

Problem

I want to make ReactJS work with Django. I don't know where everything fits in the big picture. I don't know where to start.

Solution

Are you ready? Cool.

> Pre-reqs
  • Python
  • Django
  • NodeJS
  • Bower
> Summary
  1. Start a Django project.
  2. Prepare your Django templates.
  3. Install Django packages.
  4. Install core JavaScript dependencies.
  5. Use Bower to install React and other client-level dependencies.
  6. Configure Django to use django-pipeline.
  7. Write your Django templates.
  8. Write a test React app.
  9. Collect static files and compile dependencies.
  10. Create a Django URL for the template where your React app will live.

GO!

0. Set up your virtual environment.

We don't begin without first isolating our python dependencies. I use virtualenvwrapper. Some use vanilla virtualenv. Same shit -- one doesn't smell, the other does:

$ mkvirtualenv mysite

1. Start a Django project.

Start your Django project:

$ python django-project.py startproject mysite

Go to the project folder:

$ cd mysite

Create folders to hold static files templates:

$ mkdir static templates

Create folders specifically for JavaScript and CSS files:

$ mkdir static/js static/templates

Make sure everything's fine by trying to run your Django project. If you don't know how to at this point, check out the official Django tutorial.

2. Prepare your templates.

Your React app needs to be loaded into something, right? So where will your React app live? In a template! A regular-old HTML template.

Create your main templates (assuming you're in your site root mysite/):

$ touch templates/base.html templates/index.html

The index will inherit from the base.

3. Install Django packages.

We'll install everything in one line:

$ pip install djangorestframework django-pipeline django-pipeline-browserify

Basically, we installed DRF for our API and two packages for organizing our static assets.

Django REST Framework will be used to get/pass around data in our React app. The API can be used by React to interact with our Django backend.

django-pipeline will be used for streamlining the process of collecting static files and serving them from a minimal number of compuled resources. Essentially that means we're using django-pipeline and Browserify to reorganize our JS and CSS dependency source codes for each referencing.

4. Install core JavaScript dependencies.

In order to use django-pipeline-browserify, you need to install a the Browserify node package (assuming you have Node installed):

$ npm install -g browserify

For this project, we're also going to use the Uglify JS JavaScript compressor:

$ npm install -g uglify-js

We'll also be using the Babel plugin for Browserify:

$ npm install --save-dev babelify

5. Use Bower to download more dependencies. It's time to download React.

At this point, we have everything we need to compile our JavaScript. Now, we need React and JQuery to get our React project on its feet. We'll download the React assets for Browserify and django-pipeline to refer to when creating a compiled JavaScript dependency for our front-end.

We'll use Bower.

We're skipping the creation of a bower.json config file for Bower in order to keep this short without cheating you. But I absolutely recommend you create a bower.json at some point to keep your project sane. If something goes wrong, you want your configuration stored somewhere along with the ability to reinstall all dependencies in one command. Trust me.

In your static/js/ directory:

Download React:

$ bower install --save reactjs

Download jQuery:

$ bower install --save jquery

You should have a bower_components/ (unless you specified otherwise in a .bowerrc file) directory in your static/js/ directory now. Inside of the components directory should be a jquery folder and a react folder.

6. Configure Django to create an asset pipeline.

Now, it's time to configure Django so that your static assets are served to your application properly.

In mysite/settings.py or whichever settings file you decide on, add the following:

import os  
from os.path import abspath, basename, dirname, join, normpath

# Replace BASE_DIR with this
DJANGO_ROOT = dirname(dirname(abspath(__file__)))  
SITE_ROOT = dirname(DJANGO_ROOT)  
SITE_NAME = basename(DJANGO_ROOT)

We made convenient directory path constants for use throughout our settings script. I learned this in Two Scoops of Django, by pydanny and never turned back.

INSTALLED_APPS = (  
    ...

    'django.contrib.staticfiles',

    # Pipeline
    'pipeline',

    # DRF
    'rest_framework',
)

Here, we added django-pipeline and djangorestframework to our Django project.

# Configure templates
TEMPLATES = [  
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['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',
            ],
        },
    },
]

And here, we specified the name of our template-containing folder.

# Static files (CSS, JavaScript, Images)

STATIC_URL = '/static/'  
STATIC_ROOT = normpath(join(SITE_ROOT, 'static'))  
STATICFILES_DIRS = ()  

There, we told Django where our static files would be stored and what address prefix we need to use in order to refer to them on the web (a STATIC_URL).

# Django Pipeline (and browserify)
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'

STATICFILES_FINDERS = (  
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'pipeline.finders.PipelineFinder',
)

# browserify-specific
PIPELINE_COMPILERS = (  
    'pipeline_browserify.compiler.BrowserifyCompiler',
)

PIPELINE_CSS_COMPRESSOR = 'pipeline.compressors.NoopCompressor'  
PIPELINE_JS_COMPRESSOR = 'pipeline.compressors.uglifyjs.UglifyJSCompressor'

if DEBUG:  
    PIPELINE_BROWSERIFY_ARGUMENTS = '-t babelify'

PIPELINE_CSS = {  
    'mysite_css': {
        'source_filenames': (
            'css/style.css',
        ),
        'output_filename': 'css/mysite_css.css',
    },
}

PIPELINE_JS = {  
    'mysite_js': {
        'source_filenames': (
            'js/bower_components/jquery/dist/jquery.min.js',
            'js/bower_components/react/JSXTransformer.js',
            'js/bower_components/react/react-with-addons.js',
            'js/app.browserify.js',
        ),
        'output_filename': 'js/mysite_js.js',
    }
}

We're doing a few things here:

STATICFILES_STORAGE will tell django-pipeline how you'd like to package your files. In this case, we're going to create different versions of our packaged JS and CSS, so we're making use of pipeline_browserify.compiler.BrowserifyCompiler.

STATICFILES_FINDERS contains a django-pipeline-specific static file backend for finding the files output by django-pipeline. This is useful for when you set DEBUG = False.

PIPELINE_COMPILERS contains the Browserify compiler from django-pipeline-browserify, which tells django-pipeline to use Browserify to bundle our dependencies.

PIPELINE_CSS_COMPRESSOR is set to omit the compression step in our pipeline. Feel free to use whatever compressor you like.

PIPELINE_JS_COMPRESSOR is set to pipeline.compressors.uglifyjs.UglifyJSCompressor in order to tell django-pipeline to use UglifyJS to compress our JavaScript.

PIPELINE_BROWSERIFY_ARGUMENTS tells django-pipeline which Browserify arguments to invoke. In this case, using the -t flag, we want pipeline to specify a the babelify transform while using Browserify to package our dependencies. We're using babelify instead of reactify since React 0.14 is supposedly deprecate support for Reactify in favor of Babelify. The transform is used to correctly convert JSX into working JavaScript.

PIPELINE_CSS AND PIPELINE_JS specify the asset bundles and what they're constructed from. Specify the location of each dependency relative to your STATIC_ROOT. In this case, that's mysite/static/, and so our React and jQuery dependencies should be listed starting from js/bower_components/.

The output_filename in each PIPELINECSS/PIPELINEJS definition is used to specify. The resulting bundle file containing all of your compiled code.

mysite_css and mysite_js are the reference names we'll need for loading our static files in our Django templates.

Notice that our JavaScript entry-point file--the file that will bring in all of our dependencies--end .browserify.js. That's important. Save your entry-point assets that way so that django-pipeline-browserify can work properly.

7. Write your templates.

Almost done. Sweet.

Now, I'm assuming you're familiar with Django templates. Again, if you're not familiar with Django basics like templates, check out the official tutorial and the documentation.

Here's what base.html should look like:

base.py

{% load pipeline %}
<!DOCTYPE html>  
<html lang="en">  
  <head>
    <meta charset="utf-8">
    <title>{% block title %}{% endblock %}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Oh shit! Word?! Shit you care about but probably shouldn't.">
    <meta name="author" content="Oh shit! Word?!">

    <!-- styles -->
    {% stylesheet 'mysite_css' %}

  </head>
  <body>

    {% block content %}{% endblock %}

    <!-- JavaScript scripts -->

    {% javascript 'mysite_js' %}
  </body>
</html>  

We're using 2 django-pipeline-specific template tags: stylesheet and javascript. We use each to specify to pipeline which bundles we want to use. In this case, our CSS will be one file ane our JS will be one file (our JS entry-point). Each file will contain the dependencies that will be used to run our site.

The benefit of using Browserify (and utilities like it, like WebPack) is that with it we can compile our dependencies and use them solely in the client (the browser). That enables us to use statements like require('react'). Check out the Browserify docs for more info on this, but that's the use case in a nutshell.

Here's index.html, which contains the container div for our React application:

index.html

{% extends 'base.html' %}
{% block title %}MySite{% endblock %}

{% block content %}
<div id="content">  
</div>  
{% endblock %}

8. Write a test app.

Create css/style.css:

style.css:

body {  
  background-color: #22A7F0;
}

Create js/app.browserify.js:

app.browserify.js

'use strict';

var $ = require('jquery');  
var React = require('react');

var TestApp = React.createClass({  
  render: function() {
    return (
      <div className="page">
        <h1>Oh shit! React works!</h1>
      </div>
    );
  }
});

React.render(  
  React.createElement(TestApp, null),
  document.getElementById('content')
);

9. Collect static files and compile dependencies.

In the terminal, in your site root:

$ python manage.py collectstatic

You should see a final line that looks like this if the pipeline process was successful:

x static files copied to '/full/path/to/mysite/static', xxx unmodified, xx post-processed.  

10. Create a Django route for templates. This is where your React app will live after all!

In mysite/urls.py:

...
from django.views.generic import TemplateView

urlpatterns = [  
    ...

    # Root
    url(r'^$', TemplateView.as_view(template_name='index.html')),

]

Save. Run your server.

Conclusion

I plan to write more on actually using DRF and making API calls in your React app. But this isn't a React tutorial -- this is just a tutorial for getting React set up with Django.

I also plan on writing something on using react-router in order to make an SPA with just React and Django. I may even go as far as explaining how to use Flux with Django for those who want a full MVC on the front-end as opposed to just the React library (which is just for producing views). react-router is an entire topic in itself, though. You can do just fine with react-router and Django.

I've also decided to use this architecture for hackathons, by the way. I haven't mastered React yet, nor JavaScript (lol), but I'm doing small projects to get up to speed. If you have any project ideas, hit me up.

Also, hit me up if you have a better way of doing this. Being a newbie, I may have ran around the block a few more times than necessary.

If none of this worked, don't get mad at me, just correct me. If you have questions, let me know. If I left anything out, let me know. Email me or leave a comment.

I miss you, Renee. It's scary, but I'm doing it.

Greg

Software Engineer

Subscribe to GregBlogs