Fields¶
Ferro supports a wide range of Python types, automatically mapping them to the most efficient database types available in the Rust engine.
Supported Types¶
| Python Type | Database Type (General) | Notes |
|---|---|---|
int |
INTEGER |
|
str |
TEXT / VARCHAR |
|
bool |
BOOLEAN / INTEGER |
Stored as 0/1 in SQLite. |
float |
DOUBLE / FLOAT |
|
datetime |
DATETIME / TIMESTAMP |
Use datetime.datetime with timezone awareness. |
date |
DATE |
Use datetime.date. |
UUID |
UUID / TEXT |
Stored as a 36-character string if native UUID is unavailable. |
Decimal |
NUMERIC / DECIMAL |
Use decimal.Decimal for high-precision financial data. |
bytes |
BLOB / BYTEA |
Stored as binary data. |
Enum |
ENUM / TEXT |
Python enum.Enum (typically string-backed). |
dict / list |
JSON / JSONB |
Stored as JSON strings in SQLite. |
Field Metadata¶
Ferro supports two equivalent ways to configure database-level constraints:
typing.Annotated[..., FerroField(...)]ferro.Field(..., primary_key=..., unique=..., index=...)
Use whichever style matches your codebase best. Do not declare both styles on the same field.
Option 1: Annotated + FerroField¶
from typing import Annotated
from ferro import Model, FerroField
class Product(Model):
sku: Annotated[str, FerroField(primary_key=True)]
slug: Annotated[str, FerroField(unique=True, index=True)]
price: Annotated[Decimal, FerroField(index=True)]
Option 2: Wrapped ferro.Field¶
from decimal import Decimal
from ferro import Field, Model
class Product(Model):
sku: str = Field(primary_key=True)
slug: str = Field(unique=True, index=True)
price: Decimal = Field(index=True)
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
primary_key |
bool |
False |
Marks the field as the primary key for the table. |
autoincrement |
bool \| None |
None |
If True, the database generates values automatically. Defaults to True for integer primary keys. |
unique |
bool |
False |
Enforces a uniqueness constraint on the column. |
index |
bool |
False |
Creates a database index for this column to improve query performance. |
Pydantic Integration¶
ferro.Field wraps Pydantic's Field, so all standard Pydantic validation and schema kwargs still apply:
from ferro import Field, Model
class User(Model):
username: str = Field(
unique=True,
min_length=3,
max_length=50,
description="Public handle"
)
If you prefer Annotated, you can also compose FerroField with pydantic.Field(...) metadata in the same annotation.