Django React 2
Django React 2
(Revised)
This course provides a clear, step-by-step path to mastering full-stack web development using
React for dynamic frontends and Django for robust backends. You will learn to build modern
web applications by understanding how these powerful technologies work together.
Course Overview
This revised course is structured into 6 core modules, progressing from foundational setup to
building integrated applications and preparing for deployment.
Table of Contents
What is Full-Stack? Understanding the roles of frontend (what users see) and
backend (server logic, data).
Why React & Django? Strengths of React for dynamic UIs and Django for robust,
"batteries-included" backends.
RESTful APIs: The standard way frontend and backend communicate.
Development Workflow: Running separate development servers for each part.
Django Project:
o pip install Django django-cors-headers djangorestframework
djangorestframework-simplejwt
o django-admin startproject myproject . (creates project in current
directory)
React Project:
o npx create-react-app frontend (creates a frontend folder with React
app)
o cd frontend
o npm install bootstrap react-bootstrap (for Bootstrap) OR npm
install -D tailwindcss postcss autoprefixer and configure (for
Tailwind).
Views: Python functions or classes that receive web requests and return responses.
o Function-Based Views (FBVs): Simple functions (def my_view(request):
...).
o Class-Based Views (CBVs): More structured, often used with Django's
generic views (ListView, DetailView, CreateView, UpdateView,
DeleteView) for common patterns.
URLs: Mapping web addresses to your views.
o path(): The primary way to define URL patterns.
o include(): For modularizing URL configurations across apps.
o URL Names: Using name argument for reverse lookups ({% url
'app_name:url_name' %}).
Introduction to DRF: Why DRF is the standard for building APIs in Django.
Serializers: Converting Django models into JSON (serialization) and converting
incoming JSON into Python objects (deserialization).
rest_framework.serializers.ModelSerializer.
API Views:
o @api_view decorator for FBVs.
o APIView for basic CBVs.
o generics.* views (e.g., ListAPIView, RetrieveAPIView,
ListCreateAPIView) for common API patterns.
ViewSets & Routers: Simplifying API creation for full CRUD operations
(viewsets.ModelViewSet) and automatically generating URL patterns.
1. Setup: Ensure your React app is ready. Install your chosen styling framework
(Bootstrap or Tailwind CSS) and react-router-dom.
2. Routing: Set up React Router to have at least two main pages:
o /: A ProductListPage component.
o /products/:id: A ProductDetailPage component.
3. API Consumption:
o In ProductListPage, use useEffect to fetch all products from your Django
backend's /api/products/ endpoint.
o Display the products using your chosen styling framework (e.g., as cards in a
grid). Each product card should show its name, price, and a "View Details"
button/link that navigates to its ProductDetailPage (e.g., /products/1).
o In ProductDetailPage, use useEffect and URL parameters (useParams
from React Router) to fetch a single product from /api/products/:id/.
o Display the full product details (name, description, price, stock) on this page,
styled appropriately.
4. State Management: Use useState to manage the list of products, the single product
details, loading indicators, and any error messages.
5. Styling: Make sure your product list and detail pages are visually appealing and
responsive using your chosen framework's classes/components.
The Same-Origin Policy: Why browsers restrict requests between different origins
(domain, protocol, port).
CORS Headers: How the server tells the browser it's safe to allow cross-origin
requests.
django-cors-headers: Review its installation and configuration in settings.py
(CORS_ALLOWED_ORIGINS, CORS_ALLOW_ALL_ORIGINS).
Debugging CORS: Common errors and how to resolve them.
JWT Basics: What a JWT is (header, payload, signature), how it provides stateless
authentication for APIs.
djangorestframework-simplejwt:
o Review its installation and configuration in settings.py.
o Understanding the default JWT endpoints: /api/token/ (for obtaining tokens)
and /api/token/refresh/ (for getting new access tokens).
Authentication Flow:
1. User sends username/password to Django login endpoint.
2. Django validates credentials and returns access and refresh tokens.
3. React stores tokens (e.g., in localStorage).
4. React sends the access token in the Authorization: Bearer <token> header
for protected API requests.
React Authentication Context: Creating a global AuthContext to manage the user's
login status and tokens across your React application.
Token Refresh: Implementing logic to automatically refresh an expired access token
using the refresh token.
1. Backend (Django):
o Ensure djangorestframework-simplejwt is fully configured in
settings.py and its URLs are included.
o Modify your ProductViewSet in backend/api/views.py to require
authentication for POST, PUT, PATCH, DELETE operations (e.g.,
permission_classes = [IsAuthenticated]). GET operations can remain
public.
o (Optional but recommended) Create a simple user registration endpoint in
backend/api/views.py (e.g., a UserCreateAPIView or a custom view that
uses Django's UserCreationForm or a custom serializer).
2. Frontend (React):
o Create Login.js and Register.js components with forms.
o Implement logic to send user credentials to Django's /api/token/ (for login)
and your registration endpoint (for register).
o On successful login, store the received access and refresh tokens in
localStorage.
o Create an AuthContext (using createContext and useContext) to provide
currentUser data (e.g., id, username) and login/logout functions
throughout your app.
o Wrap your App component with the AuthContext.Provider.
o Modify your API calls (e.g., using Axios interceptors) to include the
Authorization: Bearer <access_token> header for all requests to your
Django API.
o Implement a "Logout" button in your UI that clears tokens and updates the
AuthContext.
o Protected Frontend Route: Use React Router to protect a route (e.g.,
/products/create). If the user is not authenticated, redirect them to the
/login page.
o Conditional UI: Show a "Create New Product" button on the
ProductListPage only if the user is logged in.
This module focuses on applying your full-stack knowledge to build core features found in
various types of web applications. You will extend your existing product catalog application
or start new minimal setups to implement these features.
Choose one of the following features and integrate it into your existing React/Django Product
Catalog application from previous assignments.
WSGI Server (Gunicorn): Flask's built-in server is for development only. Gunicorn
is a production-ready WSGI HTTP server for Python applications.
o Running Gunicorn: gunicorn myproject.wsgi:application --bind
0.0.0.0:8000.
Reverse Proxy (Nginx): Nginx sits in front of Gunicorn.
o Purpose: Serves static/media files, handles SSL/TLS (HTTPS), load
balancing, and acts as a security layer.
o Configuration: Basic Nginx setup to proxy API requests to Gunicorn and
serve static/media files.
Environment Variables: Crucial for managing sensitive data (database credentials,
SECRET_KEY, API keys) and configuration settings in production.
o Using python-dotenv for local development.
o Setting variables directly on the production server or via platform-specific
mechanisms.
Testing:
o Unit Tests: Testing individual components or functions in isolation (e.g.,
Django models, React components).
o Integration Tests: Testing how different parts of your application interact
(e.g., Django API endpoints with mock data, React components interacting
with a mocked API).
o Using Django's TestCase and Client for backend tests.
o Using React Testing Library for frontend tests.
Debugging:
o Using Python debuggers (e.g., pdb, VS Code debugger) for the backend.
o Using browser developer tools and React DevTools for the frontend.
o Effective logging practices.
1. Prepare your Product Catalog application: Ensure your Django backend and React
frontend are working correctly in development.
2. Backend (Django):
o In backend/myproject/settings.py, set DEBUG = False.
o Set ALLOWED_HOSTS = ['127.0.0.1', 'localhost'] (for local simulation,
or your server's IP/domain if deploying for real).
o Run python manage.py collectstatic.
o Install Gunicorn: pip install gunicorn.
o Simulate Gunicorn running: gunicorn myproject.wsgi:application --
bind 127.0.0.1:8000. Keep this running in one terminal.
3. Frontend (React):
o In your frontend directory, create a production build: npm run build. This
creates a build/ folder with optimized static files.
o Option A (Serve React via Django):
Modify backend/myproject/settings.py to point
STATICFILES_DIRS to your React build folder (e.g.,
os.path.join(BASE_DIR, '../frontend/build/static')).
Add a catch-all URL in backend/myproject/urls.py to serve
index.html for all non-API routes (e.g., re_path(r'^.*',
TemplateView.as_view(template_name='index.html'))).
Ensure index.html from your React build is accessible to Django's
template loader (you might need to copy it or adjust
TEMPLATES['DIRS']).
Run python manage.py runserver (or Gunicorn) and access
http://127.0.0.1:8000/.
o Option B (Serve React via a simple HTTP server):
Install a simple HTTP server (e.g., npm install -g serve).
Navigate to your frontend/build directory.
Run serve -s . -l 3000.
Access http://localhost:3000/ in your browser. (Ensure your
Django backend is still running on 8000).
4. Verification: Confirm that your application loads and functions correctly in a
simulated production setup. Check the browser console for any errors related to static
files or API calls.
This section provides conceptual answers to the assignments. These are outlines of the
expected approach and key components, not full code implementations.
Models (backend/api/models.py):
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField(default=0)
is_available = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self): return self.name
Migrations: python manage.py makemigrations api, python manage.py
migrate.
Admin (backend/api/admin.py): from django.contrib import admin; from
.models import Product; admin.site.register(Product).
Serializers (backend/api/serializers.py):
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
URLs (backend/api/urls.py):
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet
router = DefaultRouter()
router.register(r'products', ProductViewSet)
urlpatterns = [path('', include(router.urls))]
Routing (frontend/src/App.js):
import { BrowserRouter as Router, Routes, Route, Link } from 'react-
router-dom';
// ... import ProductListPage, ProductDetailPage
function App() {
return (
<Router>
<nav> <Link to="/">Products</Link> </nav>
<Routes>
<Route path="/" element={<ProductListPage />} />
<Route path="/products/:id" element={<ProductDetailPage />}
/>
</Routes>
</Router>
);
}
ProductListPage (frontend/src/components/ProductListPage.js):
o useState for products, loading, error.
o useEffect to fetch products from REACT_APP_API_URL/products/.
o Map products to ProductCard components.
o Use Bootstrap Container, Row, Col, Card or Tailwind grid, gap-4, shadow-
md for styling.
ProductDetailPage (frontend/src/components/ProductDetailPage.js):
o useParams to get id.
o useState for product, loading, error.
o useEffect to fetch product from REACT_APP_API_URL/products/${id}/.
o Display details. Use Bootstrap Card or Tailwind p-6, rounded-lg.
Backend:
o settings.py: Add DEFAULT_AUTHENTICATION_CLASSES to REST_FRAMEWORK
settings:
('rest_framework_simplejwt.authentication.JWTAuthentication',).
o backend/core/urls.py: Add path('api/token/',
TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(),
name='token_refresh').
o backend/api/views.py: In ProductViewSet, add permission_classes =
[IsAuthenticatedOrReadOnly] for GET and [IsAuthenticated] for
POST/PUT/DELETE.
o (Optional Register View):
o # backend/api/views.py
o from django.contrib.auth.models import User
o from rest_framework import generics, permissions
o from .serializers import UserSerializer # Create a
UserSerializer
o class RegisterView(generics.CreateAPIView):
o queryset = User.objects.all()
o permission_classes = (permissions.AllowAny,)
o serializer_class = UserSerializer
o # backend/api/urls.py: path('register/',
RegisterView.as_view(), name='register')
Frontend:
o AuthContext.js:
o import React, { createContext, useState, useEffect, useContext
} from 'react';
o const AuthContext = createContext(null);
o export const AuthProvider = ({ children }) => {
o const [authToken, setAuthToken] =
useState(localStorage.getItem('access_token'));
o const [refreshToken, setRefreshToken] =
useState(localStorage.getItem('refresh_token'));
o const [user, setUser] = useState(null);
o // ... login, logout functions, useEffect to set user from
token ...
o return (<AuthContext.Provider value={{ authToken,
refreshToken, user, login, logout
}}>{children}</AuthContext.Provider>);
o };
o export const useAuth = () => useContext(AuthContext);
Assignment 5.1: Add a Core Feature to Your Product App (Example: Shopping Cart)
Backend:
o models.py: Cart (ForeignKey to User), CartItem (ForeignKey to Cart,
ForeignKey to Product, IntegerField quantity).
o serializers.py: CartItemSerializer, CartSerializer (includes nested
CartItemSerializer).
o views.py: CartViewSet with retrieve, add_item (custom action),
update_item, remove_item methods. Protected by IsAuthenticated.
o urls.py: Register CartViewSet with router, and add custom action routes.
Frontend:
o CartContext.js: Manages cart state (items, total). Functions for addToCart,
removeFromCart, updateQuantity. Fetches/sends cart data to backend.
o ProductDetailPage: "Add to Cart" button, calls CartContext.addToCart.
o CartPage.js: Displays cart items, allows quantity/removal. Fetches cart from
backend via CartContext.
o Styling: Use Bootstrap Table, Button, Modal or Tailwind table, flex, grid
for cart UI.
Backend:
o settings.py: DEBUG = False, ALLOWED_HOSTS = ['127.0.0.1'].
o python manage.py collectstatic.
o Run Gunicorn: gunicorn myproject.wsgi:application --bind
127.0.0.1:8000.
Frontend:
o npm run build.
o Option A (Django serving React):
backend/myproject/settings.py:
import os
# ...
STATICFILES_DIRS = [
os.path.join(BASE_DIR, '../frontend/build/static'), #
Point to React's static files
]
TEMPLATES = [
{
'DIRS': [os.path.join(BASE_DIR,
'../frontend/build')], # Point to React's index.html
# ...
},
]
backend/core/urls.py:
from django.urls import path, re_path, include
from django.views.generic import TemplateView
# ...
urlpatterns = [
# ... your API paths ...
re_path(r'^(?:.*)/?$',
TemplateView.as_view(template_name='index.html')), #
Catch-all for React routes
]
Audit:
o settings.py: Confirm DEBUG=False in production, SECRET_KEY is long and
random, ALLOWED_HOSTS is specific.
o Forms: Check all POST forms (Django templates or React forms sending POST
requests) include {% csrf_token %} (for Django templates) or handle CSRF
token in React (if not using JWT only).
o Data rendering: Search for mark_safe in Django templates or
dangerouslySetInnerHTML in React and verify proper sanitization is applied
if user-generated content is involved.
o Database queries: Ensure no raw SQL queries are used with unsanitized user
input.
Testing:
o Django test:
o from django.test import TestCase, Client
o from django.urls import reverse
o # ... import User, Product, etc.
o class ProductAPISecurityTest(TestCase):
o def setUp(self):
o self.client = Client()
o self.product_data = {'name': 'Test Product', 'price':
10.00, 'stock': 5}
o # ... create a test user, get a JWT token for them ...
o def test_create_product_unauthenticated(self):
o response = self.client.post(reverse('api:product-
list'), self.product_data, content_type='application/json')
o self.assertEqual(response.status_code, 401) #
Unauthorized
o def test_create_product_with_invalid_token(self):
o response = self.client.post(reverse('api:product-
list'), self.product_data, content_type='application/json',
HTTP_AUTHORIZATION='Bearer invalidtoken')
o self.assertEqual(response.status_code, 401) #
Unauthorized
o # ... test authenticated creation ...
o React test:
o import { render, screen } from '@testing-library/react';
o import ProductListPage from '../components/ProductListPage';
o import { AuthProvider } from '../context/AuthContext'; // If
testing with context
o test('renders product list page with loading message
initially', () => {
o render(<AuthProvider><ProductListPage /></AuthProvider>);
o expect(screen.getByText(/loading
products/i)).toBeInTheDocument();
o });
Security Header:
o pip install django-csp.
o settings.py: Add 'csp.middleware.CSPMiddleware' to MIDDLEWARE.
o Configure CSP_DEFAULT_SRC = ("'self'",), CSP_SCRIPT_SRC =
("'self'", "'unsafe-inline'") (adjust as needed for your specific app,
but be cautious with unsafe-inline).
This revised course provides a clear and focused path for building full-stack web applications
with React and Django. Remember that consistent practice through coding is key to mastering
these technologies. Good luck on your full-stack development journey!