Add todo priority and due date features

- Add priority levels (low, medium, high) to Todo model
- Add due date field to Todo model
- Create Alembic migration for new fields
- Update Todo schemas to include new fields
- Enhance CRUD operations with priority and due date filtering
- Update API endpoints to support new fields
- Implement smart ordering by priority and due date
- Update documentation to reflect changes
This commit is contained in:
Automated Action 2025-06-17 02:34:55 +00:00
parent f67be35a71
commit 5b2cda28a1
6 changed files with 95 additions and 4 deletions

View File

@ -9,6 +9,9 @@ A powerful, secure RESTful API for managing tasks and todos, built with FastAPI
- Token revocation (logout)
- Role-based access control (User/Admin roles)
- 📝 Todo CRUD operations
- Priority levels (High, Medium, Low)
- Due dates for better task management
- Smart ordering by priority and due date
- 👤 User management
- 🔍 Advanced todo filtering and pagination
- 📄 API documentation (via Swagger UI and ReDoc)
@ -98,6 +101,9 @@ The `GET /api/v1/todos/` endpoint supports the following query parameters:
- `limit`: Maximum number of records to return (default: 100)
- `title`: Filter by title (contains search)
- `is_completed`: Filter by completion status (true/false)
- `priority`: Filter by priority level (low, medium, high)
- `due_date_before`: Filter for todos due before this date
- `due_date_after`: Filter for todos due after this date
## Database Schema
@ -118,6 +124,8 @@ id: Integer (Primary Key)
title: String (Indexed)
description: Text (Optional)
is_completed: Boolean (Default: False)
priority: Enum(low, medium, high) (Default: medium)
due_date: DateTime (Optional)
owner_id: Integer (Foreign Key to User)
```

View File

@ -1,3 +1,4 @@
from datetime import datetime
from typing import Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, status
@ -11,6 +12,7 @@ from app.crud.crud_todo import (
get_todos,
update_todo,
)
from app.models.todo import PriorityLevel
from app.models.user import User
from app.schemas.todo import Todo, TodoCreate, TodoUpdate
@ -24,6 +26,9 @@ def read_todos(
limit: int = 100,
title: Optional[str] = None,
is_completed: Optional[bool] = None,
priority: Optional[PriorityLevel] = None,
due_date_before: Optional[datetime] = None,
due_date_after: Optional[datetime] = None,
current_user: User = Depends(get_current_active_user),
) -> Any:
"""
@ -33,6 +38,9 @@ def read_todos(
- **limit**: Maximum number of records to return
- **title**: Filter by title (contains search)
- **is_completed**: Filter by completion status
- **priority**: Filter by priority level (low, medium, high)
- **due_date_before**: Filter for todos due before this date
- **due_date_after**: Filter for todos due after this date
"""
todos = get_todos(
db=db,
@ -40,7 +48,10 @@ def read_todos(
skip=skip,
limit=limit,
title=title,
is_completed=is_completed
is_completed=is_completed,
priority=priority,
due_date_before=due_date_before,
due_date_after=due_date_after
)
return todos

View File

@ -1,8 +1,9 @@
from datetime import datetime
from typing import List, Optional
from sqlalchemy.orm import Session
from app.models.todo import Todo
from app.models.todo import PriorityLevel, Todo
from app.schemas.todo import TodoCreate, TodoUpdate
@ -16,7 +17,10 @@ def get_todos(
skip: int = 0,
limit: int = 100,
title: Optional[str] = None,
is_completed: Optional[bool] = None
is_completed: Optional[bool] = None,
priority: Optional[PriorityLevel] = None,
due_date_before: Optional[datetime] = None,
due_date_after: Optional[datetime] = None
) -> List[Todo]:
query = db.query(Todo).filter(Todo.owner_id == owner_id)
@ -26,6 +30,18 @@ def get_todos(
if is_completed is not None:
query = query.filter(Todo.is_completed == is_completed)
if priority is not None:
query = query.filter(Todo.priority == priority)
if due_date_before is not None:
query = query.filter(Todo.due_date <= due_date_before)
if due_date_after is not None:
query = query.filter(Todo.due_date >= due_date_after)
# Order by priority (highest first) and due date (earliest first)
query = query.order_by(Todo.priority.desc(), Todo.due_date.asc())
return query.offset(skip).limit(limit).all()
@ -34,6 +50,8 @@ def create_todo(db: Session, todo_in: TodoCreate, owner_id: int) -> Todo:
title=todo_in.title,
description=todo_in.description,
is_completed=todo_in.is_completed,
priority=todo_in.priority,
due_date=todo_in.due_date,
owner_id=owner_id
)
db.add(db_todo)

View File

@ -1,9 +1,16 @@
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Text
from enum import Enum as PyEnum
from sqlalchemy import Boolean, Column, DateTime, Enum, ForeignKey, Integer, String, Text
from sqlalchemy.orm import relationship
from app.db.base import Base
class PriorityLevel(str, PyEnum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
class Todo(Base):
__tablename__ = "todos"
@ -11,6 +18,8 @@ class Todo(Base):
title = Column(String, index=True)
description = Column(Text, nullable=True)
is_completed = Column(Boolean, default=False)
priority = Column(Enum(PriorityLevel), default=PriorityLevel.MEDIUM)
due_date = Column(DateTime, nullable=True)
owner_id = Column(Integer, ForeignKey("users.id"))
owner = relationship("User", back_populates="todos")

View File

@ -1,13 +1,18 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from app.models.todo import PriorityLevel
# Shared properties
class TodoBase(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
is_completed: Optional[bool] = False
priority: Optional[PriorityLevel] = PriorityLevel.MEDIUM
due_date: Optional[datetime] = None
# Properties to receive on item creation

View File

@ -0,0 +1,40 @@
"""add todo priority and due date
Revision ID: 004
Revises: 003
Create Date: 2023-11-17
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '004'
down_revision = '003'
branch_labels = None
depends_on = None
def upgrade():
# Create priority_level enum type
with op.batch_alter_table('todos', schema=None) as batch_op:
# Add priority column
batch_op.add_column(sa.Column('priority', sa.Enum('low', 'medium', 'high', name='prioritylevel'), nullable=True))
# Set default values for existing records
batch_op.execute("UPDATE todos SET priority = 'medium' WHERE priority IS NULL")
# Make priority not nullable with default
batch_op.alter_column('priority', nullable=False, server_default='medium')
# Add due_date column
batch_op.add_column(sa.Column('due_date', sa.DateTime(), nullable=True))
def downgrade():
# Remove the new columns
with op.batch_alter_table('todos', schema=None) as batch_op:
batch_op.drop_column('due_date')
batch_op.drop_column('priority')
# Drop the enum type
op.execute('DROP TYPE prioritylevel')