Django REST API – Models, Serializers and Views
In this post, we will create the first real structure of our Django REST API.
We will define database models, convert those models into JSON using serializers, and expose the data through API views.
Understanding the API flow
Before writing code, it is useful to understand how data flows inside a Django REST Framework project.
Model → Serializer → View → URL → JSON Response
Each part has a specific responsibility.
Model → Defines the database structure
Serializer → Converts model data into JSON
View → Handles the request and returns a response
URL → Connects an endpoint to a view
Creating the Project model
Open the config/projects/models.py file and create a simple Project model.
from django.db import models
class Project(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
This model represents a project in our API.
name → Project name
description → Optional project description
created_at → Creation date
Creating the Task model
Now let’s create a Task model.
Each task will belong to a project.
from django.db import models
class Project(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Task(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='tasks')
title = models.CharField(max_length=100)
description = models.TextField(blank=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
The relationship between Project and Task is created using a foreign key.
One Project → Many Tasks
The related_name='tasks' allows us to access all tasks from a project using:
project.tasks.all()
Creating migrations
After creating or changing models, we need to create a migration file.
python manage.py makemigrations
Django will detect the new models and prepare the database changes.
Applying migrations
Now apply the migrations to the database.
python manage.py migrate
At this point, the database tables for Project and Task are created.
Registering models in the admin panel
To manage projects and tasks through the Django Admin Panel, register the models in config/projects/admin.py.
from django.contrib import admin
from .models import Project, Task
admin.site.register(Project)
admin.site.register(Task)
Now run the server and access the admin panel.
python manage.py runserver
Admin: http://localhost:8000/admin/
You can now create some projects and tasks manually through the admin interface.
What is a serializer?
A serializer is one of the most important parts of Django REST Framework.
It converts Django model instances into JSON, and it can also convert JSON data back into Django model instances.
Model instance → Serializer → JSON
JSON → Serializer → Model instance
Without serializers, we would need to manually prepare every JSON response.
Creating serializers.py
Inside the projects app, create a new file called serializers.py.
projects/
__init__.py
admin.py
apps.py
migrations/
models.py
serializers.py
tests.py
urls.py
views.py
Then add the following code:
from rest_framework import serializers
from .models import Project, Task
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
The ModelSerializer automatically creates serializer fields based on the model fields.
This means we do not need to manually define every field one by one.
Creating API views
Now we need to create views that return data through the API.
For this first example, we will use function-based views with the @api_view decorator.
Open config/projects/views.py and add the following code:
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Project, Task
from .serializers import ProjectSerializer, TaskSerializer
@api_view(['GET'])
def project_list(request):
projects = Project.objects.all()
serializer = ProjectSerializer(projects, many=True)
return Response(serializer.data)
@api_view(['GET'])
def task_list(request):
tasks = Task.objects.all()
serializer = TaskSerializer(tasks, many=True)
return Response(serializer.data)
These views return all projects and all tasks from the database as JSON responses.
Project.objects.all() → Gets all projects from the database
ProjectSerializer(... ) → Converts projects into JSON-ready data
Response(serializer.data) → Returns the API response
The many=True argument is required because we are serializing multiple objects.
Connecting views to URLs
Now we need to connect our views to API endpoints.
Open config/projects/urls.py and add the following:
from django.urls import path
from . import views
urlpatterns = [
path('projects/', views.project_list, name='project-list'),
path('tasks/', views.task_list, name='task-list'),
]
Because we already included the app URLs under /api/ in the previous post, the final endpoints will be:
http://localhost:8000/api/projects/
http://localhost:8000/api/tasks/
Testing the API in the browser
Run the development server if it is not already running.
python manage.py runserver
Then open the following URLs in your browser:
Projects: http://localhost:8000/api/projects/
Tasks: http://localhost:8000/api/tasks/
If you created projects and tasks in the admin panel, you should see a JSON response with your data.
Example JSON response
A response from the projects endpoint could look like this:
[
{
"id": 1,
"name": "Website Redesign",
"description": "Update the company website layout",
"created_at": "2026-05-05T10:30:00Z"
},
{
"id": 2,
"name": "Mobile App",
"description": "Create the first version of the mobile app",
"created_at": "2026-05-05T11:00:00Z"
}
]
At this point, we already have a simple read-only API.
What we have built
In this post, we created the first functional part of our Django REST API.
Created Project and Task models
Created database migrations
Registered models in the Django admin
Created serializers
Created API views
Connected views to URLs
Returned JSON responses
This is the foundation of a REST API with Django REST Framework.
What comes next?
In the next post, we will expand this API by adding full CRUD functionality.
Instead of only reading data, we will learn how to create, retrieve, update, and delete resources through API endpoints.
Django REST API: CRUD Endpoints