Files
temp/docs/modules/domain-base-model.md
T

4.2 KiB

Domain Base Model

Package: cleveragents.domain.models.base Introduced: v3.8.0 (issue #1941)

The DomainBaseModel is a shared Pydantic base class that centralises the common model_config previously duplicated across 14 domain model classes. All standard domain-layer Pydantic models should inherit from DomainBaseModel instead of pydantic.BaseModel directly.


Purpose

Before DomainBaseModel was introduced, every domain model file contained an identical model_config = ConfigDict(...) block. This created a maintenance burden: any change to the shared configuration had to be propagated manually to all 14 files, and it was easy for individual models to drift out of sync.

DomainBaseModel solves this by defining the configuration in exactly one place. Future changes to the shared config automatically propagate to every consumer.


Usage

from cleveragents.domain.models.base import DomainBaseModel

class MyDomainModel(DomainBaseModel):
    name: str
    value: int

That's all that's required. The model inherits all five configuration options described below.


Configuration Options

DomainBaseModel sets the following model_config options:

Option Value Effect
str_strip_whitespace True Leading/trailing whitespace is stripped from all str fields on assignment and validation
validate_assignment True Field assignments after construction are validated just like constructor arguments
arbitrary_types_allowed False All field types must be Pydantic-compatible; arbitrary Python objects are not permitted
populate_by_name True Models can be constructed using either the Python field name or the JSON alias
use_enum_values True Enum fields are stored and serialised as their underlying primitive values rather than as enum instances

Example: Whitespace Stripping

from cleveragents.domain.models.base import DomainBaseModel

class ProjectName(DomainBaseModel):
    name: str

p = ProjectName(name="  my-project  ")
assert p.name == "my-project"  # whitespace stripped automatically

Example: Assignment Validation

from cleveragents.domain.models.base import DomainBaseModel
from pydantic import field_validator

class BoundedValue(DomainBaseModel):
    count: int

    @field_validator("count")
    @classmethod
    def must_be_positive(cls, v: int) -> int:
        if v < 0:
            raise ValueError("count must be non-negative")
        return v

bv = BoundedValue(count=5)
bv.count = -1  # raises ValidationError — validate_assignment=True

Migration Guide

If you are adding a new domain model, inherit from DomainBaseModel:

# Before
from pydantic import BaseModel, ConfigDict

class MyModel(BaseModel):
    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        arbitrary_types_allowed=False,
        populate_by_name=True,
        use_enum_values=True,
    )
    name: str

# After
from cleveragents.domain.models.base import DomainBaseModel

class MyModel(DomainBaseModel):
    name: str

If you need to override one of the shared options for a specific model, you can still do so by declaring model_config on the subclass — Pydantic merges configs with the subclass taking precedence:

from pydantic import ConfigDict
from cleveragents.domain.models.base import DomainBaseModel

class SpecialModel(DomainBaseModel):
    # Allow arbitrary types for this specific model only
    model_config = ConfigDict(arbitrary_types_allowed=True)
    data: object

Scope

DomainBaseModel is intended for domain-layer models only. Do not use it for:

  • Infrastructure ORM models (use SQLAlchemy Base instead)
  • CLI output models (use plain pydantic.BaseModel or dataclasses)
  • Configuration models (use pydantic_settings.BaseSettings)