React CRUD With Django: A Complete Guide
React CRUD with Django: A Complete Guide
Hey guys! Ever wanted to build a super slick web application where your frontend, built with the awesome React , talks seamlessly to your powerful backend, powered by Django ? Well, you’ve come to the right place! In this guide, we’re going to dive deep into creating a full-stack application using React for the user interface and Django for the robust backend, focusing specifically on implementing CRUD operations. CRUD stands for Create, Read, Update, and Delete, which are the fundamental building blocks for most dynamic web applications. Think about it – every time you post a comment, edit your profile, or delete an old message, you’re interacting with CRUD functionality! We’ll break down each step, from setting up your Django project to making those essential API calls from your React app. So, buckle up, grab your favorite beverage, and let’s get this full-stack party started!
Table of Contents
Setting Up Your Django Backend
Alright, first things first, we need to get our
Django
backend up and running. This is going to be the engine that manages all our data. We’ll start by creating a new Django project and an app within it. For this example, let’s call our project
myproject
and our app
api
. Open up your terminal or command prompt and run these commands:
python -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
pip install django django-rest-framework
django-admin startproject myproject
cd myproject
python manage.py startapp api
Now, we need to add
api
to the
INSTALLED_APPS
in
myproject/settings.py
. We also need to set up our Django model. Let’s imagine we’re building a simple to-do list application. So, in
api/models.py
, we’ll define our
Todo
model:
from django.db import models
class Todo(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
After defining your model, you need to create database migrations and apply them:
python manage.py makemigrations api
python manage.py migrate
Next, we’ll set up our serializers and views using Django REST framework to create our API endpoints. This is crucial for allowing our React frontend to communicate with the Django backend. We’ll need to install Django REST framework first if you haven’t already:
pip install djangorestframework
. Then, in
api/serializers.py
(create this file if it doesn’t exist):
from rest_framework import serializers
from .models import Todo
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = '__all__'
Now, let’s create our API views in
api/views.py
. We’ll use generic API views for simplicity:
from rest_framework import generics
from .models import Todo
from .serializers import TodoSerializer
class TodoListCreate(generics.ListCreateAPIView):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
class TodoDetailUpdateDestroy(generics.RetrieveUpdateDestroyAPIView):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
Finally, we need to define our API URLs. Create
api/urls.py
:
from django.urls import path
from . import views
urlpatterns = [
path('todos/', views.TodoListCreate.as_view(), name='todo-list-create'),
path('todos/<int:pk>/', views.TodoDetailUpdateDestroy.as_view(), name='todo-detail-update-destroy'),
]
And include these URLs in your main project’s
myproject/urls.py
:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')) # Add this line
]
With these steps, your
Django backend
is now ready to serve our
React
frontend with
CRUD
capabilities. We’ve set up models, serializers, views, and URLs. The
TodoListCreate
view handles listing all todos and creating new ones (Create and Read), while
TodoDetailUpdateDestroy
handles retrieving, updating, and deleting individual todos (Read, Update, Delete). It’s pretty neat how Django REST framework simplifies all this! Remember to run your Django development server with
python manage.py runserver
to test your API endpoints using tools like Postman or
curl
.
Creating Your React Frontend
Now that our Django backend is humming along, let’s shift our focus to the frontend with React . This is where the magic happens for the user. We’ll create a new React application using Create React App (CRA), which is a fantastic tool for bootstrapping React projects. If you don’t have Node.js and npm installed, you’ll need to get those first. Then, open your terminal in the directory outside your Django project folder and run:
npx create-react-app frontend
cd frontend
This sets up a basic React project structure. Inside your
frontend
directory, you’ll find
src/App.js
, which is our main component. We’ll modify this file to include our
CRUD
logic. To interact with our Django API, we’ll use the
fetch
API, which is built into modern browsers, or you could opt for a library like
axios
for more advanced features. For this guide, let’s stick with
fetch
for simplicity.
First, let’s set up some state to hold our list of todos and manage input fields for creating and updating them. We’ll also need functions to fetch todos from the backend, create a new todo, update an existing one, and delete a todo. This is where the React CRUD part really comes to life.
In
src/App.js
:
import React, { useState, useEffect } from 'react';
import './App.css';
function App() {
const [todos, setTodos] = useState([]);
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [editingId, setEditingId] = useState(null);
const [editTitle, setEditTitle] = useState('');
const [editDescription, setEditDescription] = useState('');
const API_URL = 'http://localhost:8000/api/todos/'; // Your Django API URL
// --- Read Operation ---
useEffect(() => {
fetchTodos();
}, []);
const fetchTodos = async () => {
try {
const response = await fetch(API_URL);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setTodos(data);
} catch (error) {
console.error('Error fetching todos:', error);
}
};
// --- Create Operation ---
const handleCreateTodo = async (e) => {
e.preventDefault();
if (!title || !description) return;
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ title, description, completed: false }),
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const newTodo = await response.json();
setTodos([...todos, newTodo]);
setTitle('');
setDescription('');
} catch (error) {
console.error('Error creating todo:', error);
}
};
// --- Update Operations ---
const handleEditClick = (todo) => {
setEditingId(todo.id);
setEditTitle(todo.title);
setEditDescription(todo.description);
};
const handleUpdateTodo = async (id) => {
try {
const response = await fetch(`${API_URL}${id}/`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ title: editTitle, description: editDescription, completed: false }), // Assuming completed is managed elsewhere or default
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const updatedTodo = await response.json();
setTodos(todos.map(todo => (todo.id === id ? updatedTodo : todo)));
setEditingId(null);
setEditTitle('');
setEditDescription('');
} catch (error) {
console.error('Error updating todo:', error);
}
};
const handleCancelEdit = () => {
setEditingId(null);
setEditTitle('');
setEditDescription('');
};
// --- Delete Operation ---
const handleDeleteTodo = async (id) => {
try {
const response = await fetch(`${API_URL}${id}/`, {
method: 'DELETE',
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
setTodos(todos.filter(todo => todo.id !== id));
} catch (error) {
console.error('Error deleting todo:', error);
}
};
return (
<div className="App">
<h1>Todo List</h1>
{/* Create Todo Form */}
<form onSubmit={handleCreateTodo}>
<input
type="text"
placeholder="Todo Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
placeholder="Description"
value={description}
onChange={(e) => setDescription(e.target.value)}
></textarea>
<button type="submit">Add Todo</button>
</form>
{/* Todo List */}
<ul>
{todos.map(todo => (
<li key={todo.id}>
{editingId === todo.id ? (
<>
<input
type="text"
value={editTitle}
onChange={(e) => setEditTitle(e.target.value)}
/>
<textarea
value={editDescription}
onChange={(e) => setEditDescription(e.target.value)}
></textarea>
<button onClick={() => handleUpdateTodo(todo.id)}>Save</button>
<button onClick={handleCancelEdit}>Cancel</button>
</>
) : (
<>
<h3>{todo.title}</h3>
<p>{todo.description}</p>
<button onClick={() => handleEditClick(todo)}>Edit</button>
<button onClick={() => handleDeleteTodo(todo.id)}>Delete</button>
</>
)}
</li>
))}
</ul>
</div>
);
}
export default App;
In this React component, we’re using
useState
to manage the list of
todos
and the input values for creating and editing. The
useEffect
hook is used to fetch all the todos when the component mounts. Each
CRUD
operation is handled by a separate asynchronous function that makes a
fetch
request to our Django API. Notice how we handle the
POST
for creation,
PUT
for updates, and
DELETE
for removal. We also have a conditional rendering logic to switch between viewing a todo and editing it. This is the core of our
React CRUD
implementation interacting with Django!
Connecting Frontend and Backend: CORS Configuration
One of the most common hurdles when connecting a frontend and backend on different ports (like React on
localhost:3000
and Django on
localhost:8000
) is Cross-Origin Resource Sharing, or
CORS
. Your browser, for security reasons, prevents web pages from making requests to a different domain, subdomain, port, or protocol than the one that served the page. To allow your React app to make requests to your Django API, you need to configure CORS in your Django project. You’ll need to install
django-cors-headers
:
pip install django-cors-headers
Then, add
'corsheaders'
to your
INSTALLED_APPS
in
myproject/settings.py
:
INSTALLED_APPS = [
# ... other apps
'corsheaders',
'api',
]
And add the CORS middleware before any other middleware:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
# ... other middleware
]
Finally, you need to allow requests from your React development server. Add this to your
myproject/settings.py
:
CORS_ALLOWED_ORIGINS = [
'http://localhost:3000', # Your React app's origin
'http://127.0.0.1:3000',
]
# If you are using Webpack Dev Server, you might also need:
# CORS_ALLOW_METHODS = (
# 'DELETE',
# 'GET',
# 'OPTIONS',
# 'PATCH',
# 'POST',
# 'PUT',
# )
By setting up
CORS
correctly, you’re essentially telling your Django backend, “Hey, it’s okay for requests to come from my React development server!” This is a critical step for any full-stack application where your frontend and backend are served from different locations. Without it, your
fetch
requests from React will likely fail with CORS errors in the browser console. This configuration ensures smooth communication between your
React CRUD
components and your
Django
API endpoints.
Running Your Application
To see your masterpiece in action, you’ll need to run both your Django development server and your React development server. Make sure you are in the correct directories for each:
-
Start the Django Backend: Open your terminal, navigate to your Django project directory (
myproject), and run:python manage.py runserverThis will start your Django server, typically at
http://127.0.0.1:8000/. -
Start the React Frontend: Open a new terminal, navigate to your React application directory (
frontend), and run:npm startThis will start your React development server, usually at
http://localhost:3000/. Your browser should automatically open to this address.
Now, you should be able to see your React application. Try adding a new todo, editing an existing one, and deleting it. Each action you perform in the React interface should be reflected in your Django backend and vice-versa if you were to refresh the page or access the API directly. This full-stack React CRUD setup with Django is a powerful combination for building dynamic web applications. You’ve successfully connected your frontend and backend, enabling seamless data manipulation!
Conclusion: Your React CRUD Django Journey
And there you have it, guys! You’ve successfully built a React CRUD application powered by Django . We walked through setting up the Django backend with models, serializers, and API views, and then crafted a React frontend to interact with that API, implementing all the core CRUD operations: Create, Read, Update, and Delete. We also tackled the essential CORS configuration to ensure your frontend and backend could communicate smoothly. This is a foundational skill for any aspiring full-stack developer. With this knowledge, you can now go on to build much more complex and interactive applications. Remember, practice makes perfect, so keep experimenting and building! Happy coding!