persona-finance-tracker-demo/app/models/category.py
2025-09-13 17:40:23 +05:30

79 lines
2.5 KiB
Python

"""
Category Model
SQLAlchemy model for transaction categories.
Handles categorization of financial transactions.
"""
from datetime import datetime
from app.extensions import db
class Category(db.Model):
"""
Category model for organizing transactions.
Attributes:
id (int): Primary key
name (str): Category name (unique)
description (str): Optional description
color (str): Hex color code for UI representation
is_active (bool): Whether category is active
created_at (datetime): Creation timestamp
"""
__tablename__ = 'categories'
# Primary key
id = db.Column(db.Integer, primary_key=True)
# Category information
name = db.Column(db.String(100), nullable=False, unique=True)
description = db.Column(db.Text)
color = db.Column(db.String(7)) # Hex color code (#FFFFFF)
is_active = db.Column(db.Boolean, default=True, nullable=False)
# Timestamps
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
# Relationships
transactions = db.relationship('Transaction', backref='category', lazy=True)
def __repr__(self):
"""String representation of Category."""
return f'<Category {self.name}>'
def to_dict(self):
"""Convert category to dictionary for JSON serialization."""
return {
'id': self.id,
'name': self.name,
'description': self.description,
'color': self.color,
'is_active': self.is_active,
'created_at': self.created_at.isoformat() if self.created_at else None
}
def get_transaction_count(self):
"""Get transaction count without loading all transactions."""
from app.models.transaction import Transaction
return db.session.query(Transaction).filter_by(category_id=self.id).count()
@classmethod
def get_categories_with_counts(cls):
"""Get categories with transaction counts efficiently."""
from app.models.transaction import Transaction
return db.session.query(
cls,
db.func.count(Transaction.id).label('transaction_count')
).outerjoin(Transaction).group_by(cls.id).all()
@classmethod
def get_active_categories(cls):
"""Get all active categories."""
return cls.query.filter_by(is_active=True).all()
@classmethod
def find_by_name(cls, name):
"""Find category by name."""
return cls.query.filter_by(name=name).first()