103 lines
3.2 KiB
Python
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
|