Skip to content

aatansen/Django-Project-Management-API

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Django Project Management API

Context

Instructions

Database Plan

This section outlines the database schema for the project management application.

  • Users(Stores user details)

    • id: Primary Key
    • username: String (Unique)
    • email: String (Unique)
    • password: String
    • first_name: String
    • last_name: String
    • date_joined: DateTime
  • Projects(Stores project details)

    • id: Primary Key
    • name: String
    • description: Text
    • owner: Foreign Key (to Users)
    • created_at: DateTime
  • Project Members(Stores project members and their roles)

    • id: Primary Key
    • project: Foreign Key (to Projects)
    • user: Foreign Key (to Users)
    • role: String (Admin, Member)
  • TasksStores task details(Stores task details)

    • id: Primary Key
    • title: String
    • description: Text
    • status: String (To Do, In Progress, Done)
    • priority: String (Low, Medium, High)
    • assigned_to: Foreign Key (to Users, nullable)
    • project: Foreign Key (to Projects)
    • created_at: DateTime
    • due_date: DateTime
  • Comments(Stores comments on tasks)

    • id: Primary Key
    • content: Text
    • user: Foreign Key (to Users)
    • task: Foreign Key (to Tasks)
    • created_at: DateTime

⬆️ Go to Context

REST API Endpoints

This section describes the REST API endpoints for the project management application.

  • Users

    • Register User (POST /api/users/register/): Create a new user.
    • Login User (POST /api/users/login/): Authenticate a user and return a token.
    • Get User Details (GET /api/users/{id}/): Retrieve details of a specific user.
    • Update User (PUT/PATCH /api/users/{id}/): Update user details.
    • Delete User (DELETE /api/users/{id}/): Delete a user account.
  • Projects

    • List Projects (GET /api/projects/): Retrieve a list of all projects.
    • Create Project (POST /api/projects/): Create a new project.
    • Retrieve Project (GET /api/projects/{id}/): Retrieve details of a specific project.
    • Update Project (PUT/PATCH /api/projects/{id}/): Update project details.
    • Delete Project (DELETE /api/projects/{id}/): Delete a project.
  • Tasks

    • List Tasks (GET /api/projects/{project_id}/tasks/): Retrieve a list of all tasks in a project.
    • Create Task (POST /api/projects/{project_id}/tasks/): Create a new task in a project.
    • Retrieve Task (GET /api/tasks/{id}/): Retrieve details of a specific task.
    • Update Task (PUT/PATCH /api/tasks/{id}/): Update task details.
    • Delete Task (DELETE /api/tasks/{id}/): Delete a task.
  • Comments

    • List Comments (GET /api/tasks/{task_id}/comments/): Retrieve a list of all comments on a task.
    • Create Comment (POST /api/tasks/{task_id}/comments/): Create a new comment on a task.
    • Retrieve Comment (GET /api/comments/{id}/): Retrieve details of a specific comment.
    • Update Comment (PUT/PATCH /api/comments/{id}/): Update comment details.
    • Delete Comment (DELETE /api/comments/{id}/): Delete a comment.

⬆️ Go to Context

Implementation Steps

This section outlines the steps to implement the project management API.

  • Set up the Django Project:
    • Initialize a new Django project.
    • Set up the project configurations and create a new app for the project management functionalities.
  • Design the Database Schema:
    • Define the models according to the database schema plan.
    • Use Django's ORM to create relationships between models.
    • Migrate the database to create the necessary tables.
  • Implement the REST API:
    • Use Django REST Framework to create serializers for each model.
    • Develop viewsets for each resource and register them with the router.
    • Implement authentication using Django REST Framework or JWT token authentication.
  • Documentation:
    • Use tools like Swagger to document the API.
    • Provide clear instructions on how to set up and use the API.

⬆️ Go to Context

Implementation

Project Setup

  1. Create a Virtual Environment:

    python -m venv venv
  2. Activate the Virtual Environment:

    venv\Scripts\activate
  3. Install Dependencies:

    pip install -r requirements.txt
  4. Create the Django Project:

    django-admin startproject project_management .
  5. Create a Django App:

    python manage.py startapp core

⬆️ Go to Context

Project Structure

Django-Project-Management-API/
│
├── project_management/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
│
├── core/
│   ├── migrations/
│   ├── models.py
│   ├── serializers.py
│   ├── views.py
│   └── urls.py
│
├── requirements.txt
└── manage.py

⬆️ Go to Context

Models Implementation

  • In core/models.py, implement the Django models for the Project and Task models.

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    from django.utils.translation import gettext_lazy as _
    
    class User(AbstractUser):
        """
        Custom User model extending Django's AbstractUser
        Adds additional fields like first_name, last_name
        """
        email = models.EmailField(_('email address'), unique=True)
        date_joined = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.username
    
    class Project(models.Model):
        """
        Represents a project in the management system
        """
        name = models.CharField(max_length=200)
        description = models.TextField(blank=True)
        owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owned_projects')
        created_at = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.name
    
    class ProjectMember(models.Model):
        """
        Represents project membership and roles
        """
        ROLE_CHOICES = [
            ('admin', 'Admin'),
            ('member', 'Member')
        ]
        project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='members')
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        role = models.CharField(max_length=10, choices=ROLE_CHOICES, default='member')
    
        class Meta:
            unique_together = ('project', 'user')
    
    class Task(models.Model):
        """
        Represents tasks within a project
        """
        STATUS_CHOICES = [
            ('todo', 'To Do'),
            ('in_progress', 'In Progress'),
            ('done', 'Done')
        ]
        PRIORITY_CHOICES = [
            ('low', 'Low'),
            ('medium', 'Medium'),
            ('high', 'High')
        ]
    
        title = models.CharField(max_length=200)
        description = models.TextField(blank=True)
        status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='todo')
        priority = models.CharField(max_length=10, choices=PRIORITY_CHOICES, default='medium')
        project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='tasks')
        assigned_to = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
        created_at = models.DateTimeField(auto_now_add=True)
        due_date = models.DateTimeField(null=True, blank=True)
    
        def __str__(self):
            return self.title
    
    class Comment(models.Model):
        """
        Represents comments on tasks
        """
        content = models.TextField()
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='comments')
        created_at = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return f"Comment by {self.user.username} on {self.task.title}"

⬆️ Go to Context

Serializers

  • In core/serializers.py, implement the Django serializers for the Project and Task models.

    from rest_framework import serializers
    from .models import User, Project, ProjectMember, Task, Comment
    
    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
            fields = ['id', 'username', 'email', 'first_name', 'last_name', 'date_joined']
            read_only_fields = ['id', 'date_joined']
    
    class ProjectSerializer(serializers.ModelSerializer):
        owner = UserSerializer(read_only=True)
    
        class Meta:
            model = Project
            fields = ['id', 'name', 'description', 'owner', 'created_at']
            read_only_fields = ['id', 'created_at']
    
    class ProjectMemberSerializer(serializers.ModelSerializer):
        user = serializers.PrimaryKeyRelatedField(
            queryset=User.objects.all(), 
            required=True  # Make user required
        )
        project = serializers.PrimaryKeyRelatedField(
            queryset=Project.objects.all(), 
            required=True  # Make project required
        )
    
        class Meta:
            model = ProjectMember
            fields = ['id', 'project', 'user', 'role']
            read_only_fields = ['id']
    
        def validate(self, data):
            """
            Validation to prevent duplicate project memberships during creation
            Allow role updates for existing memberships
            """
            # Check if this is an update operation
            instance = getattr(self, 'instance', None)
            
            # If this is an update and the instance exists, allow the update
            if instance is not None:
                return data
            
            # For new memberships, check for existing membership
            existing_membership = ProjectMember.objects.filter(
                project=data['project'], 
                user=data['user']
            ).exists()
            
            if existing_membership:
                raise serializers.ValidationError("User is already a member of this project.")
            
            return data
    
        def create(self, validated_data):
            """
            Custom create method to handle project member creation
            """
            # Ensure both project and user are provided
            if 'project' not in validated_data or 'user' not in validated_data:
                raise serializers.ValidationError("Both project and user must be specified when creating a project member.")
            
            return ProjectMember.objects.create(**validated_data)
    
    class TaskSerializer(serializers.ModelSerializer):
        assigned_to = UserSerializer(read_only=True)
        project = serializers.PrimaryKeyRelatedField(
            queryset=Project.objects.all(), 
            required=True  # Make project required
        )
    
        class Meta:
            model = Task
            fields = ['id', 'title', 'description', 'status', 'priority', 
                    'project', 'assigned_to', 'created_at', 'due_date']
            read_only_fields = ['id', 'created_at']
    
        def create(self, validated_data):
            """
            Custom create method to handle task creation with project
            """
            # Ensure project is provided
            if 'project' not in validated_data:
                raise serializers.ValidationError("A project must be specified when creating a task.")
            
            return Task.objects.create(**validated_data)
    
    class CommentSerializer(serializers.ModelSerializer):
        user = UserSerializer(read_only=True)
        task = serializers.PrimaryKeyRelatedField(
            queryset=Task.objects.all(), 
            required=True  # Make task required
        )
    
        class Meta:
            model = Comment
            fields = ['id', 'content', 'user', 'task', 'created_at']
            read_only_fields = ['id', 'created_at', 'user']
    
        def create(self, validated_data):
            """
            Custom create method to handle comment creation with task
            """
            # Ensure task is provided
            if 'task' not in validated_data:
                raise serializers.ValidationError("A task must be specified when creating a comment.")
            
            return Comment.objects.create(**validated_data)

⬆️ Go to Context

Views and ViewSets

  • In core/views.py, implement the Django views for the Project and Task models.

    from rest_framework import viewsets, permissions
    from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
    from .models import User, Project, ProjectMember, Task, Comment
    from .serializers import (
        UserSerializer, ProjectSerializer, 
        ProjectMemberSerializer, TaskSerializer, CommentSerializer
    )
    from django.shortcuts import render
    
    class UserViewSet(viewsets.ModelViewSet):
        """
        API endpoint for managing users
        """
        queryset = User.objects.all()
        serializer_class = UserSerializer
        permission_classes = [permissions.IsAuthenticated]
    
        @extend_schema(
            description="List all users",
            responses={200: UserSerializer(many=True)}
        )
        def list(self, request, *args, **kwargs):
            return super().list(request, *args, **kwargs)
    
    class ProjectViewSet(viewsets.ModelViewSet):
        """
        API endpoint for managing projects
        """
        queryset = Project.objects.all()
        serializer_class = ProjectSerializer
        permission_classes = [permissions.IsAuthenticated]
    
        def perform_create(self, serializer):
            serializer.save(owner=self.request.user)
    
        @extend_schema(
            description="List all projects",
            responses={200: ProjectSerializer(many=True)}
        )
        def list(self, request, *args, **kwargs):
            return super().list(request, *args, **kwargs)
    
    class ProjectMemberViewSet(viewsets.ModelViewSet):
        """
        API endpoint for managing project members
        """
        queryset = ProjectMember.objects.all()
        serializer_class = ProjectMemberSerializer
        permission_classes = [permissions.IsAuthenticated]
    
        def perform_create(self, serializer):
            """
            Custom create method to handle project member creation
            """
            # Optionally, you can add additional logic here if needed
            # For example, only allow project owners or admins to add members
            serializer.save()
    
    class TaskViewSet(viewsets.ModelViewSet):
        """
        API endpoint for managing tasks
        """
        queryset = Task.objects.all()
        serializer_class = TaskSerializer
        permission_classes = [permissions.IsAuthenticated]
    
        def perform_create(self, serializer):
            """
            Custom create method to set the current user as the creator if not specified
            """
            # If no assigned_to is provided, default to the current user
            if not serializer.validated_data.get('assigned_to'):
                serializer.save(assigned_to=self.request.user)
            else:
                serializer.save()
    
        @extend_schema(
            description="List tasks",
            parameters=[
                OpenApiParameter(
                    name='project_id', 
                    type=OpenApiTypes.INT, 
                    location=OpenApiParameter.QUERY,
                    description="Filter tasks by project ID"
                )
            ],
            responses={200: TaskSerializer(many=True)}
        )
        def list(self, request, *args, **kwargs):
            project_id = request.query_params.get('project_id')
            if project_id:
                self.queryset = self.queryset.filter(project_id=project_id)
            return super().list(request, *args, **kwargs)
    
    class CommentViewSet(viewsets.ModelViewSet):
        """
        API endpoint for managing comments
        """
        queryset = Comment.objects.all()
        serializer_class = CommentSerializer
        permission_classes = [permissions.IsAuthenticated]
    
        def perform_create(self, serializer):
            """
            Custom create method to set the current user as the comment author
            """
            # Set the current user as the comment author
            serializer.save(user=self.request.user)
    
        @extend_schema(
            description="List comments",
            parameters=[
                OpenApiParameter(
                    name='task_id', 
                    type=OpenApiTypes.INT, 
                    location=OpenApiParameter.QUERY,
                    description="Filter comments by task ID"
                )
            ],
            responses={200: CommentSerializer(many=True)}
        )
        def list(self, request, *args, **kwargs):
            task_id = request.query_params.get('task_id')
            if task_id:
                self.queryset = self.queryset.filter(task_id=task_id)
            return super().list(request, *args, **kwargs)

⬆️ Go to Context

URLs Configuration

  • In core/urls.py, define the URL patterns for the Project and Task models.

    from django.contrib import admin
    from django.urls import path, include
    from rest_framework.routers import DefaultRouter
    from rest_framework_simplejwt.views import (
        TokenObtainPairView,
        TokenRefreshView,
    )
    from drf_spectacular.views import (
        SpectacularAPIView, 
        SpectacularRedocView, 
        SpectacularSwaggerView
    )
    
    from core.views import (
        UserViewSet, ProjectViewSet, 
        ProjectMemberViewSet, TaskViewSet, CommentViewSet
    )
    
    router = DefaultRouter()
    router.register(r'users', UserViewSet)
    router.register(r'projects', ProjectViewSet)
    router.register(r'project-members', ProjectMemberViewSet)
    router.register(r'tasks', TaskViewSet)
    router.register(r'comments', CommentViewSet)
    
    urlpatterns = [
        # Admin site
        path('admin/', admin.site.urls),
        
        # API routes
        path('api/', include(router.urls)),
        
        # Authentication routes
        path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
        path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
        
        # Swagger documentation routes
        path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
        path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
        path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
    ]

⬆️ Go to Context

Settings Configuration

  • In project_management/settings.py, configure the Django settings for the Project and Task models.

    # Add to INSTALLED_APPS
    INSTALLED_APPS = [
        ...
        'rest_framework',
        'rest_framework_simplejwt',
        'core',
    ]
    
    # Authentication
    REST_FRAMEWORK = {
        'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework_simplejwt.authentication.JWTAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.BasicAuthentication',
        ],
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
    }
    
    # Spectacular Settings
    SPECTACULAR_SETTINGS = {
        'TITLE': 'Project Management API',
        'DESCRIPTION': 'A comprehensive API for managing projects, tasks, and team collaboration',
        'VERSION': '1.0.0',
        'SERVE_INCLUDE_SCHEMA': True,
        'COMPONENT_SPLIT_REQUEST': True,
        'SWAGGER_UI_SETTINGS': {
            'deepLinking': True,
            'persistAuthorization': True,
        },
    }
    
    # Custom User Model
    AUTH_USER_MODEL = 'core.User'

⬆️ Go to Context

Final Step

  • Migrate and run the project

    python manage.py makemigrations
    python manage.py migrate
    python manage.py createsuperuser

⬆️ Go to Context

Home UI Setup

  • Create a base template in core/templates/base.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Project Management API</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
        <style>
            body { 
                background-color: #f4f6f9; 
                font-family: 'Arial', sans-serif;
            }
            .jumbotron { 
                background-color: #ffffff; 
                box-shadow: 0 4px 6px rgba(0,0,0,0.1); 
            }
            .card { 
                transition: transform 0.3s; 
                margin-bottom: 20px;
            }
            .card:hover { 
                transform: scale(1.03); 
                box-shadow: 0 10px 20px rgba(0,0,0,0.12);
            }
            .list-group-item a {
                color: #007bff;
                text-decoration: none;
            }
            .list-group-item a:hover {
                text-decoration: underline;
            }
        </style>
    </head>
    <body>
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
            <a class="navbar-brand" href="{% url 'home' %}">Project Management API</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'swagger-ui' %}">Swagger UI</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'redoc' %}">ReDoc</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'token_obtain_pair' %}">Get Token</a>
                    </li>
                </ul>
            </div>
        </nav>
    
        {% block content %}{% endblock %}
        
        <footer class="footer mt-auto py-3 bg-light text-center">
            <div class="container">
                <span class="text-muted">© 2024 Project Management API. All rights reserved.</span>
            </div>
        </footer>
    
        <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    </body>
    </html>
  • Create a home template in core/templates/home.html

    {% extends 'base.html' %}
    
    {% block content %}
    <div class="container mt-5">
        <div class="jumbotron text-center">
            <h1 class="display-4">{{ title }}</h1>
            <p class="lead">{{ description }}</p>
            <hr class="my-4">
            <p>Explore our API endpoints and manage your projects efficiently.</p>
        </div>
    
        <div class="row">
            {% for route in api_routes %}
            <div class="col-md-4 mb-4">
                <div class="card h-100">
                    <div class="card-header bg-primary text-white">
                        <h5 class="card-title mb-0">{{ route.name }}</h5>
                    </div>
                    <div class="card-body">
                        <p class="card-text">{{ route.description }}</p>
                        <ul class="list-group list-group-flush">
                            {% for endpoint in route.endpoints %}
                            <li class="list-group-item d-flex justify-content-between align-items-center">
                                <span class="badge badge-primary mr-2">{{ endpoint.method }}</span>
                                {{ endpoint.path }}
                                <small class="text-muted">{{ endpoint.description }}</small>
                            </li>
                            {% endfor %}
                        </ul>
                    </div>
                </div>
            </div>
            {% endfor %}
        </div>
    
        <div class="row mt-4">
            <div class="col-12">
                <div class="card">
                    <div class="card-header bg-success text-white">
                        <h5 class="card-title mb-0">Quick Links</h5>
                    </div>
                    <div class="card-body">
                        <div class="row">
                            <div class="col-md-4">
                                <h6>API Routes</h6>
                                <ul class="list-unstyled">
                                    <li><a href="{% url 'api:user-list' %}" class="btn btn-outline-primary btn-sm mb-2">Users API</a></li>
                                    <li><a href="{% url 'api:project-list' %}" class="btn btn-outline-primary btn-sm mb-2">Projects API</a></li>
                                    <li><a href="{% url 'api:task-list' %}" class="btn btn-outline-primary btn-sm mb-2">Tasks API</a></li>
                                </ul>
                            </div>
                            <div class="col-md-4">
                                <h6>Authentication</h6>
                                <ul class="list-unstyled">
                                    <li><a href="{% url 'token_obtain_pair' %}" class="btn btn-outline-primary btn-sm mb-2">Obtain Token</a></li>
                                    <li><a href="{% url 'token_refresh' %}" class="btn btn-outline-primary btn-sm mb-2">Refresh Token</a></li>
                                </ul>
                            </div>
                            <div class="col-md-4">
                                <h6>Documentation</h6>
                                <ul class="list-unstyled">
                                    <li><a href="{% url 'swagger-ui' %}" class="btn btn-outline-info btn-sm mb-2">Swagger UI</a></li>
                                    <li><a href="{% url 'redoc' %}" class="btn btn-outline-info btn-sm mb-2">ReDoc</a></li>
                                    <li><a href="{% url 'schema' %}" class="btn btn-outline-info btn-sm mb-2">OpenAPI Schema</a></li>
                                </ul>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    {% endblock %}
  • Create a home view in core/views.py

    def home_view(request):
        """
        Home page view that provides an overview of the Project Management API
        """
        api_routes = [
            {
                'name': 'Users',
                'description': 'Manage user accounts',
                'endpoints': [
                    {'method': 'GET', 'path': '/api/users/', 'description': 'List all users'},
                    {'method': 'POST', 'path': '/api/users/', 'description': 'Create a new user'},
                ]
            },
            {
                'name': 'Projects',
                'description': 'Manage project details',
                'endpoints': [
                    {'method': 'GET', 'path': '/api/projects/', 'description': 'List all projects'},
                    {'method': 'POST', 'path': '/api/projects/', 'description': 'Create a new project'},
                ]
            },
            {
                'name': 'Tasks',
                'description': 'Manage project tasks',
                'endpoints': [
                    {'method': 'GET', 'path': '/api/tasks/', 'description': 'List all tasks'},
                    {'method': 'POST', 'path': '/api/tasks/', 'description': 'Create a new task'},
                ]
            },
            {
                'name': 'Authentication',
                'description': 'JWT Token Management',
                'endpoints': [
                    {'method': 'POST', 'path': '/api/token/', 'description': 'Obtain JWT token'},
                    {'method': 'POST', 'path': '/api/token/refresh/', 'description': 'Refresh JWT token'},
                ]
            },
            {
                'name': 'Documentation',
                'description': 'API Documentation',
                'endpoints': [
                    {'method': 'GET', 'path': '/api/docs/', 'description': 'Swagger UI'},
                    {'method': 'GET', 'path': '/api/redoc/', 'description': 'ReDoc Documentation'},
                    {'method': 'GET', 'path': '/api/schema/', 'description': 'OpenAPI Schema'},
                ]
            }
        ]
        
        context = {
            'title': 'Project Management API',
            'description': 'A comprehensive API for managing projects, tasks, and team collaboration',
            'api_routes': api_routes
        }
        return render(request, 'home.html', context)
  • Update home URL pattern in core/urls.py

    from django.contrib import admin
    from django.urls import path, include
    from rest_framework.routers import DefaultRouter
    from rest_framework_simplejwt.views import (
        TokenObtainPairView,
        TokenRefreshView,
    )
    from drf_spectacular.views import (
        SpectacularAPIView, 
        SpectacularRedocView, 
        SpectacularSwaggerView
    )
    
    from core.views import (
        UserViewSet, ProjectViewSet, 
        ProjectMemberViewSet, TaskViewSet, CommentViewSet,
        home_view
    )
    
    router = DefaultRouter()
    router.register(r'users', UserViewSet)
    router.register(r'projects', ProjectViewSet)
    router.register(r'project-members', ProjectMemberViewSet)
    router.register(r'tasks', TaskViewSet)
    router.register(r'comments', CommentViewSet)
    
    urlpatterns = [
        # Home route
        path('', home_view, name='home'),
        
        # Admin site
        path('admin/', admin.site.urls),
        
        # API routes
        path('api/', include((router.urls, 'api'), namespace='api')),
        
        # Authentication routes
        path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
        path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
        
        # Swagger documentation routes
        path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
        path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
        path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
    ]

⬆️ Go to Context

Features

Core Components

Models

  • User: Custom user model with email and date_joined
  • Project: Represents a project with name, description, owner
  • ProjectMember: Manages user roles in projects
  • Task: Tracks project tasks with status, priority, assignment
  • Comment: Allows commenting on tasks

⬆️ Go to Context

Authentication

  • Uses JWT (JSON Web Token) authentication
  • Endpoints for token obtain and refresh
  • Supports multiple authentication methods:
    • JWT Authentication
    • Session Authentication
    • Basic Authentication

⬆️ Go to Context

API Endpoints

  • Users
    • List/Create users
    • Retrieve/Update/Delete user details
  • Projects
    • List/Create projects
    • Retrieve/Update/Delete project details
    • Manage project members
  • Tasks
    • List tasks (can filter by project)
    • Create/Update/Delete tasks
    • Assign tasks to users
  • Comments
    • Add comments to tasks
    • List/Update/Delete comments
  • Authentication
    • /api/token/: Obtain JWT token
    • /api/token/refresh/: Refresh JWT token

⬆️ Go to Context

Documentation

  • Swagger UI: Interactive API documentation
  • ReDoc: Alternative documentation view
  • OpenAPI Schema endpoint

⬆️ Go to Context

Key Features

  • Role-based access control
  • Project membership management
  • Task tracking with status and priority
  • Commenting system
  • JWT-based authentication

⬆️ Go to Context

Technology Stack

  • Django 5.1.4
  • Django REST Framework
  • drf-spectacular (OpenAPI documentation)
  • Simple JWT (Authentication)
  • SQLite (Development database)

⬆️ Go to Context

Workflow Example

  1. Create a user
  2. Obtain JWT token
  3. Create a project
  4. Add project members
  5. Create tasks
  6. Add comments to tasks

⬆️ Go to Context

Security Considerations

  • JWT authentication
  • Permissions control
  • User-specific data access

⬆️ Go to Context

Development Setup

# Create virtual environment
python -m venv venv
source venv/bin/activate
# On Windows: venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

# Setup database
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser


## Running the Project

```bash
# In Terminal
python manage.py runserver

⬆️ Go to Context

Postman/API Testing

  • Use JWT token for authenticated requests
  • Endpoints available at /api/
  • Swagger UI for interactive documentation

⬆️ Go to Context

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published