Add advanced filtering, sorting, and pagination to Todo list endpoint
This commit is contained in:
parent
25fd3c49f2
commit
38273684c4
13
README.md
13
README.md
@ -5,6 +5,7 @@ A deadass simple Todo API built with FastAPI and SQLite. This project provides a
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- RESTful API endpoints for Todo resource (Create, Read, Update, Delete)
|
- RESTful API endpoints for Todo resource (Create, Read, Update, Delete)
|
||||||
|
- Advanced filtering, sorting, and pagination capabilities
|
||||||
- SQLite database with SQLAlchemy ORM
|
- SQLite database with SQLAlchemy ORM
|
||||||
- Database migrations with Alembic
|
- Database migrations with Alembic
|
||||||
- Health check endpoint
|
- Health check endpoint
|
||||||
@ -66,7 +67,17 @@ The API will be available at http://localhost:8000
|
|||||||
- `GET /health` - Check API and database health
|
- `GET /health` - Check API and database health
|
||||||
|
|
||||||
### Todo Management
|
### Todo Management
|
||||||
- `GET /api/v1/todos` - Get all todos (with optional pagination and filtering)
|
- `GET /api/v1/todos` - Get all todos (with advanced filtering, sorting, and pagination)
|
||||||
|
- Filtering options:
|
||||||
|
- `completed`: Filter by completion status (true/false)
|
||||||
|
- `created_after`: Filter todos created on or after date (YYYY-MM-DD)
|
||||||
|
- `created_before`: Filter todos created on or before date (YYYY-MM-DD)
|
||||||
|
- Sorting options:
|
||||||
|
- `sort_by`: Field to sort by (id, title, created_at, updated_at)
|
||||||
|
- `sort_order`: Sort direction (asc, desc)
|
||||||
|
- Pagination:
|
||||||
|
- `skip`: Number of items to skip
|
||||||
|
- `limit`: Maximum number of items to return
|
||||||
- `GET /api/v1/todos/{todo_id}` - Get a specific todo by ID
|
- `GET /api/v1/todos/{todo_id}` - Get a specific todo by ID
|
||||||
- `POST /api/v1/todos` - Create a new todo
|
- `POST /api/v1/todos` - Create a new todo
|
||||||
- `PUT /api/v1/todos/{todo_id}` - Update an existing todo
|
- `PUT /api/v1/todos/{todo_id}` - Update an existing todo
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
from datetime import datetime, date
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status, Response, Query
|
from fastapi import APIRouter, Depends, HTTPException, status, Response, Query
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
from sqlalchemy import desc, asc
|
||||||
|
|
||||||
from app.db.database import get_db
|
from app.db.database import get_db
|
||||||
from app.models.todo import Todo as TodoModel
|
from app.models.todo import Todo as TodoModel
|
||||||
@ -31,23 +33,58 @@ def read_todos(
|
|||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100,
|
||||||
completed: Optional[bool] = Query(None, description="Filter by completion status"),
|
completed: Optional[bool] = Query(None, description="Filter by completion status"),
|
||||||
|
created_after: Optional[date] = Query(None, description="Filter todos created after this date (YYYY-MM-DD)"),
|
||||||
|
created_before: Optional[date] = Query(None, description="Filter todos created before this date (YYYY-MM-DD)"),
|
||||||
|
sort_by: str = Query("id", description="Field to sort by (id, title, created_at, updated_at)"),
|
||||||
|
sort_order: str = Query("asc", description="Sort order (asc or desc)"),
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Get all todo items with optional filtering.
|
Get all todo items with optional filtering, sorting, and pagination.
|
||||||
|
|
||||||
- **skip**: Number of items to skip (pagination)
|
- **skip**: Number of items to skip (pagination)
|
||||||
- **limit**: Maximum number of items to return
|
- **limit**: Maximum number of items to return (pagination)
|
||||||
- **completed**: Optional filter by completion status
|
- **completed**: Optional filter by completion status (true/false)
|
||||||
|
- **created_after**: Filter todos created on or after this date (format: YYYY-MM-DD)
|
||||||
|
- **created_before**: Filter todos created on or before this date (format: YYYY-MM-DD)
|
||||||
|
- **sort_by**: Field to sort by (options: id, title, created_at, updated_at)
|
||||||
|
- **sort_order**: Sort order (options: asc, desc)
|
||||||
|
|
||||||
Returns a list of todo items.
|
Returns a list of todo items.
|
||||||
"""
|
"""
|
||||||
query = db.query(TodoModel)
|
query = db.query(TodoModel)
|
||||||
|
|
||||||
# Apply filter if completed parameter is provided
|
# Apply filters
|
||||||
if completed is not None:
|
if completed is not None:
|
||||||
query = query.filter(TodoModel.completed == completed)
|
query = query.filter(TodoModel.completed == completed)
|
||||||
|
|
||||||
|
if created_after:
|
||||||
|
# Convert date to datetime with time at start of day (00:00:00)
|
||||||
|
start_datetime = datetime.combine(created_after, datetime.min.time())
|
||||||
|
query = query.filter(TodoModel.created_at >= start_datetime)
|
||||||
|
|
||||||
|
if created_before:
|
||||||
|
# Convert date to datetime with time at end of day (23:59:59)
|
||||||
|
end_datetime = datetime.combine(created_before, datetime.max.time())
|
||||||
|
query = query.filter(TodoModel.created_at <= end_datetime)
|
||||||
|
|
||||||
|
# Apply sorting
|
||||||
|
if sort_by not in ["id", "title", "created_at", "updated_at"]:
|
||||||
|
sort_by = "id" # Default to id if invalid field provided
|
||||||
|
|
||||||
|
if sort_order.lower() not in ["asc", "desc"]:
|
||||||
|
sort_order = "asc" # Default to ascending if invalid order provided
|
||||||
|
|
||||||
|
# Get the attribute to sort by
|
||||||
|
sort_attr = getattr(TodoModel, sort_by)
|
||||||
|
|
||||||
|
# Apply sorting direction
|
||||||
|
if sort_order.lower() == "desc":
|
||||||
|
query = query.order_by(desc(sort_attr))
|
||||||
|
else:
|
||||||
|
query = query.order_by(asc(sort_attr))
|
||||||
|
|
||||||
|
# Apply pagination
|
||||||
todos = query.offset(skip).limit(limit).all()
|
todos = query.offset(skip).limit(limit).all()
|
||||||
return todos
|
return todos
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user