Skip to content

Unify SQLAlchemy schemas and Pydantic models using SQLModel #173

@nanotaboada

Description

@nanotaboada

Description

The application currently defines football player models in two layers:

  • schemas/player_schema.py (SQLAlchemy ORM class used for DB operations)
  • models/player_model.py (Pydantic model for request/response validation)

This results in:

  • Duplicated attributes across files
  • Maintenance overhead when the schema evolves
  • Redundant translation logic between SQLAlchemy and Pydantic

Proposed Solution

Introduce SQLModel to consolidate the Player ORM and data validation layers. SQLModel extends both SQLAlchemy and Pydantic, allowing a single class to serve as:

  • The ORM model for database operations
  • The Pydantic model for validation and OpenAPI docs

This will simplify the model architecture while preserving existing behavior.

Suggested Approach

  1. Install SQLModel
pip install sqlmodel
  1. Create a new SQLModel-based class in models/player_model.py (or optionally models/player_sqlmodel.py during migration):
from typing import Optional
from sqlmodel import SQLModel, Field

class Player(SQLModel, table=True):
    __tablename__ = "players"

    id: Optional[int] = Field(default=None, primary_key=True)
    first_name: str = Field(alias="firstName")
    middle_name: Optional[str] = Field(default=None, alias="middleName")
    last_name: str = Field(alias="lastName")
    date_of_birth: Optional[str] = Field(default=None, alias="dateOfBirth")
    squad_number: int = Field(alias="squadNumber", unique=True)
    position: str
    abbr_position: Optional[str] = Field(default=None, alias="abbrPosition")
    team: Optional[str] = None
    league: Optional[str] = None
    starting11: Optional[bool] = None

Note: Field(..., alias="camelCaseName") preserves existing naming and OpenAPI compatibility.

  1. Update route handlers and services to use Player from SQLModel directly for both DB and validation.

  2. Remove the old Player class from schemas/player_schema.py and PlayerModel from models/player_model.py.

  3. Update tests and factories/stubs to use the new unified model.

Acceptance Criteria

  • A single Player class using SQLModel represents both DB schema and API schema
  • Redundant Pydantic and SQLAlchemy Player models are removed
  • Database CRUD operations continue to function
  • FastAPI auto-generates OpenAPI docs from SQLModel model as expected
  • CamelCase field naming preserved in OpenAPI and response payloads
  • Existing integration tests pass without regressions
  • Models are still serializable and validate inputs correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpythonPull requests that update Python code

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions