User CRUD REST API in Django REST Framework
In this tutorial, you’ll learn how to build a full-featured REST API for managing users using Django REST Framework (DRF). The API supports create, read, update, and delete (CRUD) operations, including image upload. It is fully frontend-ready — perfect for Angular, React, or any SPA.
✅ Features Covered
- User Registration with profile image
- View all users or a single user
- Update user data including password and image
- Delete user
- Frontend integration via FormData
📁 Project Structure
usercrud/
├── manage.py
├── usercrud/
│ ├── settings.py
│ └── urls.py
├── users/
│ ├── models.py
│ ├── serializers.py
│ ├── views.py
│ ├── urls.py
1️⃣ Install and Set Up Django
pip install django djangorestframework pillow
django-admin startproject usercrud
cd usercrud
python manage.py startapp users
2️⃣ Configure settings.py
Add to INSTALLED_APPS
:
'rest_framework',
'corsheaders',
'users',
Enable media file upload:
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
CORS_ALLOW_ALL_ORIGINS = True
3️⃣ Create CustomUser Model
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("Email is required")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
if password:
user.set_password(password)
user.save()
return user
class CustomUser(AbstractBaseUser):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(unique=True)
image = models.ImageField(upload_to='profile_images/', blank=True, null=True)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
4️⃣ Make Migrations
python manage.py makemigrations
python manage.py migrate
5️⃣ Create Serializer
from rest_framework import serializers
from .models import CustomUser
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
class Meta:
model = CustomUser
fields = ['id', 'first_name', 'last_name', 'email', 'password', 'image']
def create(self, validated_data):
password = validated_data.pop('password', None)
user = CustomUser(**validated_data)
if password:
user.set_password(password)
user.save()
return user
def update(self, instance, validated_data):
password = validated_data.pop('password', None)
for attr, value in validated_data.items():
setattr(instance, attr, value)
if password:
instance.set_password(password)
instance.save()
return instance
6️⃣ Create ViewSet
from rest_framework import viewsets
from .models import CustomUser
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = UserSerializer
7️⃣ Wire Up URLs
users/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import UserViewSet
router = DefaultRouter()
router.register('users', UserViewSet)
urlpatterns = [
path('', include(router.urls)),
]
usercrud/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('users.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
✅ API Endpoints
GET /api/users/
– List all usersPOST /api/users/
– Create userGET /api/users/<id>/
– View userPUT/PATCH /api/users/<id>/
– Update userDELETE /api/users/<id>/
– Delete user