from datetime import datetime
from typing import Optional
from sqlmodel import SQLModel, Field, Relationship, Column, String, Text
from pydantic import field_validator
class PostBase(SQLModel):
"""Base post model with shared fields."""
title: str = Field(min_length=1, max_length=200, sa_column=Column(String(200)))
content: str = Field(sa_column=Column(Text))
is_published: bool = Field(default=False)
@field_validator("title")
@classmethod
def validate_title(cls, v: str) -> str:
if not v.strip():
raise ValueError("Title cannot be empty or only whitespace")
return v.strip()
@field_validator("content")
@classmethod
def validate_content(cls, v: str) -> str:
if not v.strip():
raise ValueError("Content cannot be empty or only whitespace")
if len(v.strip()) < 10:
raise ValueError("Content must be at least 10 characters long")
return v.strip()
class Post(PostBase, table=True):
"""Post database model."""
id: Optional[int] = Field(default=None, primary_key=True)
author_id: int = Field(foreign_key="user.id")
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: Optional[datetime] = Field(default=None)
published_at: Optional[datetime] = Field(default=None)
# Relationships
author: "User" = Relationship(back_populates="posts")
class PostCreate(PostBase):
"""Post creation model."""
pass
class PostRead(PostBase):
"""Post read model."""
id: int
author_id: int
created_at: datetime
updated_at: Optional[datetime] = None
published_at: Optional[datetime] = None
class PostUpdate(SQLModel):
"""Post update model."""
title: Optional[str] = Field(default=None, min_length=1, max_length=200)
content: Optional[str] = None
is_published: Optional[bool] = None
@field_validator("title")
@classmethod
def validate_title(cls, v: Optional[str]) -> Optional[str]:
if v is not None:
if not v.strip():
raise ValueError("Title cannot be empty or only whitespace")
return v.strip()
return v
@field_validator("content")
@classmethod
def validate_content(cls, v: Optional[str]) -> Optional[str]:
if v is not None:
if not v.strip():
raise ValueError("Content cannot be empty or only whitespace")
if len(v.strip()) < 10:
raise ValueError("Content must be at least 10 characters long")
return v.strip()
return v