Create Django REST API with Image Upload | User Insert, Update, Delete | Full Tutorial

Create Django REST API with Image Upload | User Insert, Update, Delete | Full Tutorial

AI Reading

Quick summary of this article

This tutorial walks through building a Django REST API for user management with profile picture uploads. It covers project setup, MySQL database connection, user model creation with secure password hashing, serializers, viewsets, and REST endpoints for full CRUD operations.

  • Users can be created with first name, last name, email, password, and an uploaded profile image.
  • Passwords are automatically hashed using Django's built-in make_password function before saving.
  • The API uses Django REST Framework's ModelViewSet, providing standard create, read, update, and delete endpoints out of the box.
  • MySQL is configured as the database, with media files (uploaded images) stored in a dedicated media directory.
  • Testing is done via the browser at http://127.0.0.1:8000/api/users/ or through tools like Postman using multipart/form-data for image uploads.

Introduction

In this tutorial, you’ll learn how to build a complete Django REST API that allows you to create users with an image upload (profile picture). You’ll learn how to set up a Django project, create an app, connect to a MySQL database, create serializers and viewsets, and finally expose REST endpoints to create, retrieve, update, and delete user profiles.

Key Features

  • User creation with first name, last name, email, and password
  • Secure password hashing
  • Image upload for profile pictures
  • REST API using Django REST Framework (DRF)
  • MySQL integration

Project Structure

Once your project is set up, your structure will look like this:


crudwithimage/
├── db.sqlite3 (optional)
├── manage.py
├── accounts/
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── serializers.py
│   ├── tests.py
│   ├── urls.py
│   ├── views.py
│   ├── __init__.py
│   └── migrations/
│       └── __init__.py
├── crudwithimage/
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py
└── media/
    └── profile_images/
        └── [uploaded images]
  

Step 1: Install Django and DRF


pip install django djangorestframework mysqlclient pillow
  

Step 2: Create Django Project and App


django-admin startproject crudwithimage
cd crudwithimage
python manage.py startapp accounts
  

Step 3: Configure Installed Apps

In crudwithimage/settings.py, add:


INSTALLED_APPS = [
    ...
    "rest_framework",
    "accounts",
]
  

Step 4: Set Up Media and MySQL

In settings.py:


import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "djnagocrudimage",
        "USER": "myadmin",
        "PASSWORD": "Angular13#@123",
        "HOST": "localhost",
        "PORT": "3306",
    }
}
  

Step 5: Define the User Model

In accounts/models.py:


from django.db import models
from django.contrib.auth.hashers import make_password

class UserProfile(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)
    password = models.CharField(max_length=128)
    image = models.ImageField(upload_to="profile_images/")

    def save(self, *args, **kwargs):
        if not self.pk:
            self.password = make_password(self.password)
        super(UserProfile, self).save(*args, **kwargs)

    def __str__(self):
        return self.email
  

Step 6: Make and Apply Migrations


python manage.py makemigrations
python manage.py migrate
  

Step 7: Create Serializer

In accounts/serializers.py:


from rest_framework import serializers
from .models import UserProfile

class UserProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserProfile
        fields = ["id", "first_name", "last_name", "email", "password", "image"]
        extra_kwargs = {
            "password": {"write_only": True}
        }
  

Step 8: Create ViewSet

In accounts/views.py:


from rest_framework import viewsets
from .models import UserProfile
from .serializers import UserProfileSerializer

class UserProfileViewSet(viewsets.ModelViewSet):
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSerializer
  

Step 9: Register Routes

In accounts/urls.py:


from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import UserProfileViewSet

router = DefaultRouter()
router.register(r'users', UserProfileViewSet)

urlpatterns = [
    path("", include(router.urls)),
]
  

Step 10: Include in Main URLs

In crudwithimage/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("accounts.urls")),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  

Step 11: Test Your API

Run the server:


python manage.py runserver
  

Visit http://127.0.0.1:8000/api/users/ in your browser or use Postman.

Sample POST Request (Create User)


POST /api/users/
Content-Type: multipart/form-data

{
  "first_name": "John",
  "last_name": "Doe",
  "email": "john@example.com",
  "password": "secure123",
  "image": [upload file]
}
  

Conclusion

You’ve successfully created a Django REST API that supports user registration and image upload. You used Django REST Framework, MySQL, and Pillow for image handling. This is a solid foundation you can expand on — for example, adding JWT auth, image validation, or deploying to production.

What’s Next?

  • Add authentication (JWT with djangorestframework-simplejwt)
  • Integrate file storage services like AWS S3 or Cloudinary
  • Use Django signals to send welcome emails on user creation
  • Build a React frontend for the API

Leave a Reply

Your email address will not be published. Required fields are marked *