Skip to content

Model types

The model_type option controls what kind of class the plugin generates for each table. All four produce the same fields with the same annotations - they differ only in the class machinery and dependencies.

options:
  model_type: "msgspec"   # dataclass | attrs | msgspec | pydantic

The four forms

Given this table:

CREATE TABLE test_field_namings
(
    id      bigint PRIMARY KEY NOT NULL,
    outputs jsonb              NOT NULL
);

the plugin generates (shown with the default docstrings: none):

@dataclasses.dataclass()
class TestFieldNaming:
  id_: int
  outputs: str

Standard library, no dependencies. The safe default.

Which to pick: dataclass if you want zero dependencies, msgspec for speed and JSON, pydantic for runtime validation, attrs for its ergonomics.

Pydantic specifics

model_type: pydantic differs from the others in two ways worth knowing:

  • arbitrary_types_allowed=True is set on every model. It is required for field types pydantic has no core schema for (memoryview for bytea/blob, and custom override types). Those fields are still validated with an isinstance check; all other fields get full validation.
  • Runtime annotations. Unlike the other model types, pydantic resolves field annotations at runtime, so generated files import referenced modules at module level instead of inside if typing.TYPE_CHECKING:.
If you lint generated pydantic code with ruff, set lint.flake8-type-checking.runtime-evaluated-base-classes = ["pydantic.BaseModel"] so it does not try to move those runtime imports into a TYPE_CHECKING block.