Skip to content

Models

Defining a Model

Models extend VellumBaseModel and use standard Pydantic v2 field declarations:

from vellum import VellumBaseModel

class Product(VellumBaseModel):
    name: str
    price: float
    tags: list[str] = []
    metadata: dict = {}

Every model automatically includes:

Field Type Description
id UUID Auto-generated primary key (stored as _id in MongoDB)
created_at datetime UTC timestamp set on creation
updated_at datetime UTC timestamp updated on every change

Collection Name

Set a custom collection name via the inner Settings class:

class Product(VellumBaseModel):
    name: str

    class Settings:
        collection_name = "products"

If collection_name is not set, it defaults to the lowercase class name (product).

Serialization

# MongoDB-ready dict (id as string, by_alias)
doc = product.to_mongo()
# {"_id": "uuid-string", "name": "Widget", ...}

# Restore from MongoDB dict
restored = Product.from_mongo(doc)

Mixins

Optimistic Concurrency

from vellum import OptimisticConcurrencyMixin

class Product(OptimisticConcurrencyMixin, VellumBaseModel):
    name: str

Adds a version: int = 1 field. The repository auto-increments it on update and raises OptimisticLockError on stale writes.

Soft Delete

from vellum import SoftDeleteMixin

class Post(SoftDeleteMixin, VellumBaseModel):
    title: str

Adds deleted_at: datetime | None. Soft-deleted documents are excluded from find() and get() by default. See Soft Delete for details.

Both Together

class VersionedPost(OptimisticConcurrencyMixin, SoftDeleteMixin, VellumBaseModel):
    title: str

Order matters — OptimisticConcurrencyMixin first, then SoftDeleteMixin, then VellumBaseModel.

Field References

Vellum provides two equivalent ways to reference model fields for queries and sorts:

# Direct syntax (Beanie-style)
Product.price > 10
Product.name == "Widget"

# Fields proxy syntax
Product.fields.price > 10
Product.fields.name == "Widget"

Both produce the same QueryExpression objects. See Queries for details.

Indexes

Define indexes in Settings using the type-safe Index class:

from vellum import Index

class Product(VellumBaseModel):
    name: str
    email: str

    class Settings:
        collection_name = "products"
        indexes = [
            Index("name"),
            Index("email", unique=True),
            Index("name", "price"),               # compound index
            Index("created_at", expireAfterSeconds=3600),  # TTL index
        ]

Or use the raw dict format (still supported):

indexes = [
    {"key": [("name", 1)]},
    {"key": [("email", 1)], "unique": True},
]

Field names are validated against the model at runtime. Create indexes with:

await repo.ensure_indexes()

Encryption

Encrypt individual fields transparently:

from vellum import encrypted_field

class User(VellumBaseModel):
    name: str
    ssn: encrypted_field("your-passphrase")  # auto encrypt/decrypt

Uses PBKDF2HMAC-SHA256 + Fernet symmetric encryption. Values are encrypted on serialization and decrypted on load.