Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

DEV Community

Cover image for How to Build a Task Manager API with Django REST Framework: Part 4 - Personalize with User-Owned Tasks
kihuni
kihuni

Posted on • Edited on

How to Build a Task Manager API with Django REST Framework: Part 4 - Personalize with User-Owned Tasks

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

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
Enter fullscreen mode Exit fullscreen mode

Apply Migrations

Run these commands to update your database:
bash

python manage.py makemigrations tasks
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

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).

migrations

  • 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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

What’s Changed?

  • Added authentication_classes = [TokenAuthentication] to both views for clarity, matching the global DEFAULT_AUTHENTICATION_CLASSES set in Part 3.
  • Used get_queryset() to filter tasks by self.request.user.
  • Added perform_create() to set created_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
Enter fullscreen mode Exit fullscreen mode

1. Register Two Users

User 1:
Method: POST

URL: http://127.0.0.1:8000/api/register/

Body: raw > JSON:

{
    "username": "user1",
    "password": "pass123"
}
Enter fullscreen mode Exit fullscreen mode

Send. Copy the token.

Postman

User 2:

Same URL, Body:

{
    "username": "user2",
    "password": "pass123"
}
Enter fullscreen mode Exit fullscreen mode

Send. Copy the token

postman test

2. Log In

For user1: POST to http://127.0.0.1:8000/api/login/, Body:

{
    "username": "user1",
    "password": "pass123"
}
Enter fullscreen mode Exit fullscreen mode

Expect {"token": "token1"}.

postman

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

test postman

Body: raw > JSON:


{
    "title": "User1 Task",
    "description": "Task for User1",
    "completed": false
}
Enter fullscreen mode Exit fullscreen mode

postman

Send. Expect 201 Created.

User 2:
Same URL, Headers: Token token2, Body:

{
    "title": "User2 Task",
    "description": "Task for User2",
    "completed": false
}
Enter fullscreen mode Exit fullscreen mode

postman

4. Access Tasks

With User 1’s Token:

postman

With User 2’s Token:

  • Same URL, Headers: Token token2
  • Send. Expect 200 OK with [{"title": "User2 Task", ...}].

postman

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).

postman

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!

Top comments (0)