Paramclasses Academy - Blog

Tutorials Details

←
Post 21 of 29
→

Django REST Framework CRUD APIs: GET, POST, PUT, PATCH, DELETE, and Retrieve API Endpoints

Django REST Framework CRUD APIs: GET, POST, PUT, PATCH, DELETE, and Retrieve API Endpoints

October 21, 2026

Introduction

Django REST Framework (DRF) provides powerful tools for building APIs that allow applications to create, retrieve, update, and delete database records. These operations are commonly known as CRUD operations.

CRUD stands for Create, Read, Update, and Delete. In a real-world application, these operations are essential for managing students, employees, products, patients, orders, and other records.

In the previous module, you learned the fundamentals of Django REST Framework, serializers, API views, and JSON responses. In this module, you will build a complete Student Management CRUD API using HTTP methods such as GET, POST, PUT, PATCH, and DELETE.

What You Will Learn

  • What CRUD operations are.

  • How to retrieve all records using GET.

  • How to retrieve a single record using its ID.

  • How to create records using POST.

  • How to update records using PUT.

  • How to partially update records using PATCH.

  • How to delete records using DELETE.

  • How to handle missing records and validation errors.

  • How to use HTTP status codes correctly.

  • How to organize and test CRUD API endpoints.

1. Understanding CRUD Operations

CRUD represents the four fundamental operations performed on database records.

Operation HTTP Method Purpose
Create POST Add a new record
Read GET Retrieve records
Update PUT or PATCH Modify an existing record
Delete DELETE Remove a record

For example, a Student Management API might provide these endpoints:

GET     /api/students/
GET     /api/students/1/
POST    /api/students/
PUT     /api/students/1/
PATCH   /api/students/1/
DELETE  /api/students/1/

Here, 1 represents the student's primary key.

2. Project Setup

Make sure Django REST Framework is installed:

pip install djangorestframework

Add the application and DRF to INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
    # Default Django applications
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",

    # Third-party application
    "rest_framework",

    # Your application
    "students",
]

This tutorial assumes that you already have a Django project and a students application.

3. Creating the Student Model

Open students/models.py.

from django.db import models


class Student(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)
    course = models.CharField(max_length=100)

    def __str__(self):
        return self.name

Run the migrations:

python manage.py makemigrations
python manage.py migrate

Explanation:

  • name stores the student's name.

  • email stores a unique email address.

  • course stores the student's course.

  • __str__() returns the student's name as a readable representation.

If your project already contains a compatible Student model, reuse it rather than creating a duplicate.

4. Creating the Student Serializer

Create students/serializers.py.

from rest_framework import serializers
from .models import Student


class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = ["id", "name", "email", "course"]
        read_only_fields = ["id"]

Explanation:

  • ModelSerializer generates serializer fields based on the model.

  • fields specifies which fields are included in the API.

  • read_only_fields prevents clients from assigning the ID directly.

  • is_valid() checks submitted data before it is saved.

5. GET API: Retrieve All Students

A GET request retrieves data without creating or modifying records.

Open students/views.py.

from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Student
from .serializers import StudentSerializer


@api_view(["GET"])
def student_list_api(request):
    students = Student.objects.all().order_by("id")
    serializer = StudentSerializer(students, many=True)

    return Response(serializer.data)

URL configuration — students/urls.py

from django.urls import path
from .views import student_list_api

urlpatterns = [
    path("students/", student_list_api, name="student_list_api"),
]

Include the application URLs in the main project urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", include("students.urls")),
]

Start the server:

python manage.py runserver

Open:

http://127.0.0.1:8000/api/students/

Example response:

[
    {
        "id": 1,
        "name": "Rahul Sharma",
        "email": "rahul@example.com",
        "course": "Python"
    },
    {
        "id": 2,
        "name": "Priya Verma",
        "email": "priya@example.com",
        "course": "Django"
    }
]

If no student records exist, the API returns an empty JSON list.

Important: many=True is required because the serializer is processing multiple student objects.

6. GET API: Retrieve a Single Student

Sometimes an application needs the details of one particular student.

Add this view to students/views.py:

from django.shortcuts import get_object_or_404


@api_view(["GET"])
def student_detail_api(request, pk):
    student = get_object_or_404(Student, pk=pk)
    serializer = StudentSerializer(student)

    return Response(serializer.data)

Add the URL to students/urls.py:

from .views import student_detail_api

urlpatterns = [
    path("students/", student_list_api, name="student_list_api"),
    path(
        "students/<int:pk>/",
        student_detail_api,
        name="student_detail_api"
    ),
]

Example URL:

http://127.0.0.1:8000/api/students/1/

Example response:

{
    "id": 1,
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "course": "Python"
}

Explanation:

  • <int:pk> captures the student's primary key from the URL.

  • get_object_or_404() retrieves the matching student.

  • If the record does not exist, Django returns a 404 response.

  • StudentSerializer(student) serializes one object, so many=True is not needed.

7. POST API: Create a New Student

A POST request creates a new student record.

Add this view to students/views.py:

from rest_framework import status


@api_view(["POST"])
def student_create_api(request):
    serializer = StudentSerializer(data=request.data)

    if serializer.is_valid():
        student = serializer.save()

        return Response(
            StudentSerializer(student).data,
            status=status.HTTP_201_CREATED
        )

    return Response(
        serializer.errors,
        status=status.HTTP_400_BAD_REQUEST
    )

Add this URL:

path("students/create/", student_create_api, name="student_create_api"),

Send a POST request to:

http://127.0.0.1:8000/api/students/create/

Example JSON request body:

{
    "name": "Amit Kumar",
    "email": "amit@example.com",
    "course": "Django"
}

How it works:

  1. The client submits student information.

  2. request.data provides the parsed request data.

  3. The serializer validates the submitted values.

  4. serializer.save() creates the record.

  5. The API returns the new record with HTTP 201 Created.

  6. Invalid data produces HTTP 400 Bad Request and validation errors.

Important: Because the email field is unique, attempting to create another student with the same email should fail validation.

8. PUT API: Update an Entire Record

A PUT request is generally used to replace the editable representation of an existing resource. In this example, the client must submit all required editable fields.

Add this view to students/views.py:

@api_view(["PUT"])
def student_update_api(request, pk):
    student = get_object_or_404(Student, pk=pk)

    serializer = StudentSerializer(
        student,
        data=request.data
    )

    if serializer.is_valid():
        student = serializer.save()

        return Response(
            StudentSerializer(student).data,
            status=status.HTTP_200_OK
        )

    return Response(
        serializer.errors,
        status=status.HTTP_400_BAD_REQUEST
    )

Add the URL:

path(
    "students/<int:pk>/update/",
    student_update_api,
    name="student_update_api"
),

Example endpoint:

PUT /api/students/1/update/

Example JSON request:

{
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "course": "Advanced Django"
}

Explanation:

  • The view retrieves the existing record.

  • The serializer validates the submitted fields.

  • serializer.save() updates the record.

  • A successful update returns HTTP 200 OK.

Important: In this example, partial is not enabled. Required fields must be supplied. If you omit a required field, validation may fail.

9. PATCH API: Update Selected Fields

A PATCH request updates only the fields provided by the client.

For example, suppose a student's course changes, but their name and email remain the same.

Add this view:

@api_view(["PATCH"])
def student_partial_update_api(request, pk):
    student = get_object_or_404(Student, pk=pk)

    serializer = StudentSerializer(
        student,
        data=request.data,
        partial=True
    )

    if serializer.is_valid():
        student = serializer.save()

        return Response(
            StudentSerializer(student).data,
            status=status.HTTP_200_OK
        )

    return Response(
        serializer.errors,
        status=status.HTTP_400_BAD_REQUEST
    )

Add the URL:

path(
    "students/<int:pk>/partial-update/",
    student_partial_update_api,
    name="student_partial_update_api"
),

Example request:

PATCH /api/students/1/partial-update/

Request body:

{
    "course": "Advanced Python"
}

Only the course is changed. The student's name and email remain unchanged.

Key difference:

  • PUT: Requires the full set of required editable fields in this implementation.

  • PATCH: Allows the client to submit only the fields it wants to change.

10. DELETE API: Delete a Student

A DELETE request removes an existing student record.

Add this view:

@api_view(["DELETE"])
def student_delete_api(request, pk):
    student = get_object_or_404(Student, pk=pk)
    student.delete()

    return Response(
        status=status.HTTP_204_NO_CONTENT
    )

Add the URL:

path(
    "students/<int:pk>/delete/",
    student_delete_api,
    name="student_delete_api"
),

Example endpoint:

DELETE /api/students/1/delete/

A successful deletion returns HTTP 204 No Content.

Important: A 204 response has no response body. In a real application, ensure that the user is authenticated and authorized to delete the selected record before allowing this operation.

11. Complete API URL Structure

Your students/urls.py can contain the following endpoints:

from django.urls import path
from .views import (
    student_list_api,
    student_detail_api,
    student_create_api,
    student_update_api,
    student_partial_update_api,
    student_delete_api,
)

urlpatterns = [
    path(
        "students/",
        student_list_api,
        name="student_list_api"
    ),
    path(
        "students/<int:pk>/",
        student_detail_api,
        name="student_detail_api"
    ),
    path(
        "students/create/",
        student_create_api,
        name="student_create_api"
    ),
    path(
        "students/<int:pk>/update/",
        student_update_api,
        name="student_update_api"
    ),
    path(
        "students/<int:pk>/partial-update/",
        student_partial_update_api,
        name="student_partial_update_api"
    ),
    path(
        "students/<int:pk>/delete/",
        student_delete_api,
        name="student_delete_api"
    ),
]

Note: Django checks URL patterns in order. These patterns are arranged so that the fixed create/ route is checked before the integer-based detail route.

12. Understanding HTTP Status Codes

Use meaningful status codes so that API clients can understand the result of a request.

Status Code Meaning Example
200 OK Request succeeded Retrieving or updating a record
201 Created New resource created Successful POST request
204 No Content Operation succeeded without a response body Successful DELETE request
400 Bad Request Submitted data is invalid Missing required fields
401 Unauthorized Authentication is missing or invalid Protected API without valid credentials
403 Forbidden User is not permitted to perform an operation Insufficient permissions
404 Not Found Record does not exist Requesting an unknown student ID
405 Method Not Allowed HTTP method is unsupported Sending POST to a GET-only endpoint

Important: The examples above use get_object_or_404() for missing records, which produces a 404 response.

13. Testing CRUD APIs with Postman

Use Postman or the DRF Browsable API to test the endpoints.

Test 1: Retrieve all students

  • Method: GET

  • URL: /api/students/

Test 2: Retrieve one student

  • Method: GET

  • URL: /api/students/1/

Test 3: Create a student

  • Method: POST

  • URL: /api/students/create/

  • Body: Raw JSON with name, email, and course.

Test 4: Update a student

  • Method: PUT

  • URL: /api/students/1/update/

  • Body: Submit all required editable fields.

Test 5: Update one field

  • Method: PATCH

  • URL: /api/students/1/partial-update/

  • Body: Submit only the field to change.

Test 6: Delete a student

  • Method: DELETE

  • URL: /api/students/1/delete/

After each operation, use GET to confirm the resulting database state.

14. Common Mistakes and Solutions

Mistake 1: Forgetting many=True

When serializing a queryset containing multiple objects, use:

StudentSerializer(students, many=True)

Mistake 2: Using partial=True with PUT unintentionally

If your PUT endpoint should require all editable fields, do not set partial=True. Use partial=True for a partial update.

Mistake 3: Forgetting serializer validation

Always call serializer.is_valid() before saving client-submitted data.

Mistake 4: Not handling missing records

Use get_object_or_404() or handle DoesNotExist explicitly to return a meaningful 404 response.

Mistake 5: Returning a response body with status 204

A 204 response should not include a response body.

Mistake 6: Leaving destructive endpoints unprotected

Do not assume that an obscure URL protects an API. Configure authentication and permissions and verify the caller is allowed to modify or delete the target record.

15. API Security Best Practices

Before using CRUD APIs in production:

  • Authentication: Require appropriate authentication for protected endpoints.

  • Permissions: Check whether the current user can perform the requested operation.

  • Object-level access: Prevent users from accessing or changing records they do not own or manage.

  • Validation: Validate all incoming data through serializers.

  • HTTPS: Use encrypted connections in production.

  • Logging: Record important administrative operations when appropriate.

  • Deletion controls: Consider confirmation, audit trails, or soft deletion where business requirements demand them.

  • Testing: Test valid requests, invalid data, missing records, and unauthorized access.

Important: The sample views are intended for learning. They do not automatically enforce user-specific permissions. Add the appropriate security rules before deploying them publicly.

16. Frequently Asked Questions (FAQs)

Q1. What does CRUD stand for?

CRUD stands for Create, Read, Update, and Delete.

Q2. What is the difference between PUT and PATCH?

PUT is generally used to replace a resource representation, while PATCH is used for partial modification. In the examples in this module, PUT requires the required editable fields and PATCH allows selected fields.

Q3. Why is get_object_or_404() useful?

It retrieves a matching record or returns a 404 response when the record does not exist.

Q4. What does serializer.save() do?

It saves validated data by creating or updating an object, depending on how the serializer was initialized.

Q5. Why does a successful DELETE request return 204?

HTTP 204 means the operation succeeded and no response body is being returned.

Q6. Can a CRUD API be used by a mobile application?

Yes. Mobile applications can send HTTP requests to the API and use the returned JSON data.

Q7. Is a CRUD API secure by default?

Not necessarily. Authentication, permissions, object-level authorization, validation, and deployment security must be configured as required.

17. Django REST Framework Interview Questions and Answers

Q1. What are CRUD operations?

Answer: CRUD stands for Create, Read, Update, and Delete. These are the basic operations for managing stored data.

Q2. Which HTTP method is commonly used to create a resource?

Answer: POST.

Q3. Which HTTP methods are commonly used for updates?

Answer: PUT and PATCH.

Q4. What is the difference between GET and POST?

Answer: GET retrieves information, while POST commonly submits data to create a resource.

Q5. What is the purpose of partial=True?

Answer: It allows a serializer to validate a partial update without requiring every normally required field.

Q6. What is the purpose of status.HTTP_201_CREATED?

Answer: It represents HTTP status 201, indicating that a resource has been created.

Q7. How can an API return a 404 response for a missing object?

Answer: Use Django's get_object_or_404() or explicitly handle a missing record.

18. Practical Assignment

Create a complete Student Management CRUD API using Django REST Framework.

Requirements:

  1. Create a Student model with name, email, and course.

  2. Create a StudentSerializer.

  3. Build a GET endpoint to list all students.

  4. Build a GET endpoint to retrieve one student.

  5. Build a POST endpoint to create a student.

  6. Build a PUT endpoint to update a student's editable fields.

  7. Build a PATCH endpoint to update selected fields.

  8. Build a DELETE endpoint to remove a student.

  9. Return appropriate HTTP status codes.

  10. Handle missing records and invalid data.

  11. Test every endpoint using Postman.

  12. Add authentication and permissions before considering the project production-ready.

Expected Result:

You should have a working CRUD API that supports all four database operations and demonstrates the use of GET, POST, PUT, PATCH, and DELETE requests.

Conclusion

In this module, you learned how to create a complete CRUD API using Django REST Framework. You implemented list, detail, create, full update, partial update, and delete endpoints while learning about serializers, URL patterns, HTTP status codes, validation, and API testing.

These skills are essential for building REST APIs for student management systems, e-commerce platforms, hospital management systems, employee portals, and other real-world applications.

In the next module, you will learn about Django REST Framework Generic Views and Mixins, including ListAPIView, RetrieveAPIView, CreateAPIView, UpdateAPIView, DestroyAPIView, and reusable API logic.

←
Post 21 of 29
→