DEV Community

Welcome back to our Django REST Framework (DRF) series! In Part 1, we set up our Django project with DRF. Part 2 added CRUD functionality for tasks, and Part 3 secured it with token authentication. In Part 4, we’re personalizing our Task Manager API—ensuring each user only sees and manages their tasks. This step makes your API truly user-specific!
By the end, your API will link tasks to their creators and restrict access accordingly, all tested with Postman. Ready to jump in?
Let’s dive in!
Table of Contents
- Step 1: Update the Task Model
- Step 2: Modify Views for User Ownership
- Step 3: Test with Postman
- Conclusion
- What’s Next?
Step 1: Update the Task Model
To tie tasks to their creators, add a created_by
field to the Task model.
Update tasks/models.py
Add a foreign key to the User
model:
from django.db import models
from django.contrib.auth.models import User
class Task(models.Model):
title = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
Apply Migrations
Run these commands to update your database:
bash
python manage.py makemigrations tasks
python manage.py migrate
NOTE: If you have existing tasks, Django will ask for a default value for created_by
. You can:
- Set a default user ID (e.g., 1 for the first user).
- Or delete db.sqlite3 (after backing up) and rerun migrations.
What’s this?
- The
created_by
field links each task to its creator. -
on_delete=models.CASCADE
removes tasks if the user is deleted.
Step 2: Modify Views for User Ownership
We need to update both the views and the serializer to handle user ownership. The view will set created_by
automatically, and the serializer will ensure created_by
isn’t required in the request.
Update tasks/serializers.py
Make created_by read-only so it’s not required in the request:
from rest_framework import serializers
from .models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ['id', 'title', 'description', 'completed', 'created_at', 'created_by']
read_only_fields = ['id', 'created_at', 'created_by'] # Make created_by read-only
Update tasks/views.py
Modify the TaskListCreateView
and TaskDetailView
:
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication
from .models import Task
from .serializers import TaskSerializer
class TaskListCreateView(generics.ListCreateAPIView):
serializer_class = TaskSerializer
permission_classes = [IsAuthenticated]
authentication_classes = [TokenAuthentication]
def get_queryset(self):
# Only show tasks created by the authenticated user
return Task.objects.filter(created_by=self.request.user)
def perform_create(self, serializer):
# Automatically set the creator when a task is created
serializer.save(created_by=self.request.user)
class TaskDetailView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = TaskSerializer
permission_classes = [IsAuthenticated]
authentication_classes = [TokenAuthentication]
def get_queryset(self):
# Only allow access to tasks created by the authenticated user
return Task.objects.filter(created_by=self.request.user)
What’s Changed?
- Added
authentication_classes = [TokenAuthentication]
to both views for clarity, matching the globalDEFAULT_AUTHENTICATION_CLASSES
set in Part 3. - Used
get_queryset()
to filter tasks byself.request.user
. - Added
perform_create()
to setcreated_by
on task creation. This ensures users only see and edit their tasks, building on the authentication from Part 3 of the series.
Step 3: Test with Postman
Start your server:
python manage.py runserver
1. Register Two Users
User 1:
Method: POST
URL: http://127.0.0.1:8000/api/register/
Body: raw > JSON:
{
"username": "user1",
"password": "pass123"
}
Send. Copy the token.
User 2:
Same URL, Body:
{
"username": "user2",
"password": "pass123"
}
Send. Copy the token
2. Log In
For user1: POST to http://127.0.0.1:8000/api/login/
, Body:
{
"username": "user1",
"password": "pass123"
}
Expect {"token": "token1"}.
For user2: Same, expect {"token": "token2"}.
3. Add Tasks
User 1:
Method: POST
URL: http://127.0.0.1:8000/api/tasks/
Headers: Authorization: Token 130194a73c000f377f782214619e8bb8f3d69412
Body: raw > JSON:
{
"title": "User1 Task",
"description": "Task for User1",
"completed": false
}
Send. Expect 201 Created.
User 2:
Same URL, Headers: Token token2, Body:
{
"title": "User2 Task",
"description": "Task for User2",
"completed": false
}
4. Access Tasks
With User 1’s Token:
- Method: GET
- URL: http://127.0.0.1:8000/api/tasks/
- Headers: Token token1
- Send. Expect 200 OK with [{"title": "User1 Task", ...}].
With User 2’s Token:
- Same URL, Headers: Token token2
- Send. Expect 200 OK with [{"title": "User2 Task", ...}].
5. Test Access to Other User’s Tasks
User 2 Tries to Access User 1’s Task:
Method: GET
- URL:
http://127.0.0.1:8000/api/tasks/1/
- Headers: Token token2
- Send. Expect 404 Not Found (because get_queryset filters out tasks not owned by User2).
Conclusion
🎉Your Task Manager API now personalizes tasks—users only see and manage their to-dos. By adding created_by and filtering in the views, we’ve made the API user-specific while keeping it secure with token authentication.
Summary Checklist
- ✅Added created_by to the Task model
- ✅Updated the serializer to make created_by read-only
- ✅Modified views to filter and assign tasks by user
- ✅Tested with Postman to confirm ownership
What’s Next?
In Part 5, we’ll optimize the API with filtering, pagination, and search—to enhance our API’s usability. Stay tuned!
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)