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

103 lines
3.2 KiB
Python

"""
Category Marshmallow Schema
Validation and serialization schema for Category model.
Handles input validation, data transformation, and JSON serialization.
"""
from marshmallow import Schema, fields, validate, validates, ValidationError
import re
class CategorySchema(Schema):
"""
Schema for Category model validation and serialization.
Provides input validation for:
- Name: Required, 1-100 characters, unique
- Description: Optional text field
- Color: Optional hex color code validation
- is_active: Boolean field with default True
"""
# Fields with validation
id = fields.Integer(dump_only=True) # Read-only field
name = fields.String(
required=True,
validate=[
validate.Length(min=1, max=100, error="Name must be 1-100 characters"),
validate.Regexp(
r'^[a-zA-Z0-9\s\-_&]+$',
error="Name can only contain letters, numbers, spaces, hyphens, underscores, and ampersands"
)
]
)
description = fields.String(
allow_none=True,
validate=validate.Length(max=500, error="Description cannot exceed 500 characters")
)
color = fields.String(
allow_none=True,
validate=validate.Length(equal=7, error="Color must be exactly 7 characters (e.g., #FF5733)")
)
is_active = fields.Boolean(load_default=True)
created_at = fields.DateTime(dump_only=True, format='iso')
@validates('color')
def validate_color(self, value, **kwargs):
"""Validate hex color format."""
if value is not None:
# Check if it's a valid hex color code
hex_pattern = r'^#[0-9A-Fa-f]{6}$'
if not re.match(hex_pattern, value):
raise ValidationError("Color must be a valid hex code (e.g., #FF5733)")
class Meta:
"""Schema configuration."""
ordered = True # Preserve field order in output
class CategoryCreateSchema(CategorySchema):
"""Schema for creating new categories."""
class Meta:
"""Schema configuration for creation."""
exclude = ('id', 'created_at')
ordered = True
class CategoryUpdateSchema(CategorySchema):
"""Schema for updating existing categories."""
# Make all fields optional for partial updates
name = fields.String(
required=False,
validate=[
validate.Length(min=1, max=100, error="Name must be 1-100 characters"),
validate.Regexp(
r'^[a-zA-Z0-9\s\-_&]+$',
error="Name can only contain letters, numbers, spaces, hyphens, underscores, and ampersands"
)
]
)
class Meta:
"""Schema configuration for updates."""
exclude = ('id', 'created_at')
ordered = True
class CategoryListSchema(Schema):
"""Schema for category list with optional transaction count."""
id = fields.Integer()
name = fields.String()
description = fields.String(allow_none=True)
color = fields.String(allow_none=True)
is_active = fields.Boolean()
created_at = fields.DateTime(format='iso')
transaction_count = fields.Integer(allow_none=True)
class Meta:
"""Schema configuration."""
ordered = True