Add due date functionality to Todo model
- Add due_date field as nullable DateTime with timezone support - Add is_overdue property to check if task is overdue - Add days_until_due property for time calculations - Create migration 007 to add due_date column with index - Maintain backward compatibility with nullable due_date
This commit is contained in:
parent
ab8e9a826d
commit
7251fea2ba
32
alembic/versions/007_add_due_date.py
Normal file
32
alembic/versions/007_add_due_date.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
"""Add due_date field to todos table
|
||||||
|
|
||||||
|
Revision ID: 007
|
||||||
|
Revises: 006
|
||||||
|
Create Date: 2025-06-19 12:00:00.000000
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "007"
|
||||||
|
down_revision = "006"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# Add due_date column to todos table
|
||||||
|
op.add_column(
|
||||||
|
"todos",
|
||||||
|
sa.Column("due_date", sa.DateTime(timezone=True), nullable=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add index for better performance on due date queries
|
||||||
|
op.create_index(op.f("ix_todos_due_date"), "todos", ["due_date"], unique=False)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_index(op.f("ix_todos_due_date"), table_name="todos")
|
||||||
|
op.drop_column("todos", "due_date")
|
@ -2,6 +2,8 @@ from sqlalchemy import Column, Integer, String, Boolean, DateTime, Enum, Foreign
|
|||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
import enum
|
import enum
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from app.db.base import Base
|
from app.db.base import Base
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ class Todo(Base):
|
|||||||
project_id = Column(Integer, ForeignKey("projects.id"), nullable=True)
|
project_id = Column(Integer, ForeignKey("projects.id"), nullable=True)
|
||||||
category_id = Column(Integer, ForeignKey("categories.id"), nullable=True)
|
category_id = Column(Integer, ForeignKey("categories.id"), nullable=True)
|
||||||
parent_id = Column(Integer, ForeignKey("todos.id"), nullable=True)
|
parent_id = Column(Integer, ForeignKey("todos.id"), nullable=True)
|
||||||
|
due_date = Column(DateTime(timezone=True), nullable=True)
|
||||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
@ -42,3 +45,25 @@ class Todo(Base):
|
|||||||
def is_subtask(self) -> bool:
|
def is_subtask(self) -> bool:
|
||||||
"""Check if this todo is a subtask of another todo."""
|
"""Check if this todo is a subtask of another todo."""
|
||||||
return self.parent_id is not None
|
return self.parent_id is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_overdue(self) -> bool:
|
||||||
|
"""Check if this todo is overdue."""
|
||||||
|
if self.due_date is None or self.completed:
|
||||||
|
return False
|
||||||
|
return datetime.now(timezone.utc) > self.due_date
|
||||||
|
|
||||||
|
@property
|
||||||
|
def days_until_due(self) -> Optional[int]:
|
||||||
|
"""Calculate the number of days until the due date.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: Number of days until due (negative if overdue)
|
||||||
|
None: If no due date is set
|
||||||
|
"""
|
||||||
|
if self.due_date is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
delta = (self.due_date - now).days
|
||||||
|
return delta
|
Loading…
x
Reference in New Issue
Block a user