This document discusses integrating Django, Django Rest Framework, React, Redux, and related technologies. It recommends using Webpack to bundle JavaScript assets. It provides code examples for defining React components, Redux reducers, and connecting a React frontend to a Django Rest Framework backend via API calls. The document emphasizes building reusable presentational and container components, and wiring actions and reducers to the backend via Redux middleware like redux-promise.
3. What this talk is not
• A comprehensive tutorial
• A deep dive into how these technologies works
• You WILL need to go and learn this stuff on your
own after this talk
4.
5.
6.
7.
8. {% extends "base.html" %}
{% load staticfiles %}
{% block title %}Some Awesome Django Website{% endblock %}
{% block extrahead %}
<link rel="stylesheet" href="{% static "some.css" %}"/>
<link rel="stylesheet" href="{% static "even_more.css" %}"/>
{% endblock %}
{% block body %}
<!-- some content in Django template -->
<div id="todolist"></div>
<!-- more content in Django template -->
{% endblock %}
9.
10. Javascript Ecosystem
• We’ll be using NPM to manage your packages
• We’ll be using webpack to handle bundling our
assets.
• We’ll be using scotch to burn away the memories of
configuring the build system for our project.
11. in a nutshell
• The pip & cheeseshop / pypi of javascript
• packages.json works like requirements.txt &
setup.py
• `npm init` in directory with packages.json generates
node_modules. Kinda like a virtualenv directory.
• packages.json also can act like your `manage.py`
for your javascript code, but you populate it with
custom commands.
12. Building for Javascript
• Start coding your project, using `npm install some-package —
save` as you go. This creates and maintains your package.json.
• Setup the config file for your build tool (webpack.config.js,
gulpfile.js, Gruntfile, etc)
• Add configs for Babel, minification, and other JS stuff
• Add configs LESS, SASS, and other CSS stuff
• Plus source mapping, tests, linters, sprite sheets, etc
• Run your tool to generate bundles, having them save into your
static directory for Django to pick up.
25. Django Rest Framework
• The Web browsable API is a huge usability win for your developers.
• Authentication policies including packages for OAuth1a and
OAuth2.
• Serialization that supports both ORM and non-ORM data sources.
• Customizable all the way down - just use regular function-based
views if you don't need the more powerful features.
• Extensive documentation, and great community support.
• Used and trusted by large companies such as Mozilla and
Eventbrite.
26. Model->Serializer->ViewSet
class Todo(models.Model):
text = models.CharField(max_length=300)
marked = models.BooleanField(default=False)
class TodoSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Todo
fields = ('id', 'text', 'marked')
class TodoViewSet(viewsets.ModelViewSet):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
28. Three Principles of Redux
• Single source of truth
• State is read-only
• Changes are made with pure functions
29. Redux State Tree / Store
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
34. Presentational Components
• Are concerned with how things look.
• Use props for displaying everything
• Do not manage state at all
• Don’t emit actions, but may take callbacks that do via
props
<MyComponent
title=“No state, just props.”
barLabels={["MD", "VA", "DE", "DC"]}
barValues={[13.626332, 47.989636, 9.596008, 28.788024]}
/>
35. Container Component
• Are concerned with how things work.
• Responsible for providing data to presentational
components via props
• Also responsible for handling state changes
triggered inside a presentation component via
callback prop. These state changes are often
done via dispatching an action.
37. Wiring Redux to DRF
• Python package “django-js-reverse" for getting
your url routes in your javascript
• NPM package “redux-promise”
38. import * as types from '../constants/ActionTypes';
function deleteTodo(id) {
return fetch(Urls.todo_detail(id), {
method: 'delete',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
},
}).then(() => ({
type: types.DELETE_TODO,
id: id
}));
}
// In a component somewhere else
store.dispatch(deleteTodo(this.props.todo.id))
39. import * as types from '../constants/ActionTypes';
import * as api from ‘../path/to/MyApiLibrary';
function deleteTodo(id) {
return api.deleteTodo(id).then(() => ({
type: types.DELETE_TODO,
id: id
}));
}
// In a component somewhere else
store.dispatch(deleteTodo(this.props.todo.id))
46. class Todo(models.Model):
text = models.CharField(max_length=300)
marked = models.BooleanField(default=False)
class TodoSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Todo
fields = ('id', 'text', 'marked')
class TodoViewSet(viewsets.ModelViewSet):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
47. import * as types from '../constants/ActionTypes';
const initialState = [];
export default function todos(state=initialState, action) {
switch (action.type) {
case types.ADD_TODO:
return [...state, action.todo];
case types.DELETE_TODO:
return state.filter(todo =>
todo.id !== action.id
);
case types.EDIT_TODO:
return state.map(todo =>
todo.id === action.todo.id ? action.todo : todo
);
default:
return state;
}
}
48. import * as types from '../constants/ActionTypes';
function deleteTodo(id) {
return fetch(Urls.todo_detail(id), {
method: 'delete',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
},
}).then(() => ({
type: types.DELETE_TODO,
id: id
}));
}
// In a component somewhere else
store.dispatch(deleteTodo(this.props.todo.id))