CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-odmantic

AsyncIO MongoDB Object Document Mapper for Python using type hints

Pending
Overview
Eval results
Files

models.mddocs/

Models

ODMantic models define the structure and validation for MongoDB documents using Pydantic. Models provide type safety, data validation, and automatic serialization/deserialization between Python objects and MongoDB documents.

Capabilities

Model Base Class

Base class for MongoDB document models with full Pydantic integration.

class Model:
    """Base class for MongoDB document models."""
    
    # Class attributes
    __collection__: str  # MongoDB collection name (auto-generated from class name)
    __config__: ODMConfigDict  # Model configuration
    
    def model_copy(self, *, include=None, exclude=None, update=None, deep=False):
        """
        Create a copy of the model with optional changes.
        
        Args:
            include: Fields to include in the copy
            exclude: Fields to exclude from the copy
            update: Dictionary of field updates to apply
            deep: Whether to make a deep copy
            
        Returns:
            New model instance with changes applied
        """
    
    def copy(self, *, include=None, exclude=None, update=None, deep=False):
        """
        Create a copy of the model (deprecated, use model_copy).
        
        Args:
            include: Fields to include in the copy
            exclude: Fields to exclude from the copy
            update: Dictionary of field updates to apply
            deep: Whether to make a deep copy
            
        Returns:
            New model instance with changes applied
        """
    
    def model_update(self, **kwargs):
        """
        Update model instance in place with new values.
        
        Args:
            **kwargs: Field names and new values
            
        Returns:
            Self for method chaining
        """
    
    def update(self, **kwargs):
        """
        Update model instance in place (deprecated, use model_update).
        
        Args:
            **kwargs: Field names and new values
            
        Returns:
            Self for method chaining
        """
    
    def model_dump_doc(self, *, include=None, exclude=None, by_alias=False, 
                      exclude_unset=False, exclude_defaults=False, exclude_none=False):
        """
        Convert model to MongoDB document dictionary.
        
        Args:
            include: Fields to include in output
            exclude: Fields to exclude from output
            by_alias: Use field aliases if defined
            exclude_unset: Exclude fields that haven't been set
            exclude_defaults: Exclude fields set to their default values
            exclude_none: Exclude fields set to None
            
        Returns:
            dict: MongoDB document representation
        """
    
    def doc(self, include=None):
        """
        Convert to MongoDB document (deprecated, use model_dump_doc).
        
        Args:
            include: Fields to include in output
            
        Returns:
            dict: MongoDB document representation
        """
    
    @classmethod
    def model_validate_doc(cls, raw_doc):
        """
        Parse MongoDB document into model instance.
        
        Args:
            raw_doc: Raw MongoDB document dictionary
            
        Returns:
            Model instance parsed from document
            
        Raises:
            DocumentParsingError: If parsing fails
        """
    
    @classmethod  
    def parse_doc(cls, raw_doc):
        """
        Parse MongoDB document (deprecated, use model_validate_doc).
        
        Args:
            raw_doc: Raw MongoDB document dictionary
            
        Returns:
            Model instance parsed from document
        """

EmbeddedModel Base Class

Base class for embedded documents that can be nested within other models.

class EmbeddedModel:
    """Base class for embedded documents."""
    
    def model_update(self, **kwargs):
        """
        Update embedded model instance in place with new values.
        
        Args:
            **kwargs: Field names and new values
            
        Returns:
            Self for method chaining
        """
    
    def update(self, **kwargs):
        """
        Update embedded model instance (deprecated, use model_update).
        
        Args:
            **kwargs: Field names and new values
            
        Returns:
            Self for method chaining
        """

Configuration

class ODMConfigDict(ConfigDict):
    """Configuration dictionary for ODM models."""
    
    collection: str | None  # Custom collection name
    parse_doc_with_default_factories: bool  # Use default factories when parsing
    indexes: Callable[[], Iterable[Index | IndexModel]] | None  # Additional indexes
    
    # Pydantic options (selected subset)
    title: str | None
    json_schema_extra: dict | None  
    str_strip_whitespace: bool  
    arbitrary_types_allowed: bool  
    extra: Literal["allow", "forbid", "ignore"] | None

Usage Examples

Basic Model Definition

from odmantic import Model, Field
from typing import Optional
from datetime import datetime

class User(Model):
    name: str
    email: str = Field(unique=True)
    age: int = Field(ge=0, le=150)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    is_active: bool = True
    tags: Optional[list[str]] = None
    
    # Custom collection name (optional)
    class Config:
        collection = "users"

Model with Custom Configuration

from odmantic import Model
from odmantic.config import ODMConfigDict

class Product(Model):
    name: str
    price: float = Field(gt=0)
    description: Optional[str] = None
    
    model_config = ODMConfigDict(
        collection="products",
        extra="forbid"  # Don't allow extra fields
    )

Embedded Models

from odmantic import Model, EmbeddedModel

class Address(EmbeddedModel):
    street: str
    city: str
    country: str
    zip_code: str

class Person(Model):
    name: str
    address: Address
    work_address: Optional[Address] = None

# Usage
address = Address(
    street="123 Main St",
    city="New York", 
    country="USA",
    zip_code="10001"
)

person = Person(name="John Doe", address=address)

Model Operations

# Create instance
user = User(
    name="Alice Smith",
    email="alice@example.com", 
    age=30,
    tags=["developer", "python"]
)

# Copy with changes
updated_user = user.model_copy(update={"age": 31})

# Update in place
user.model_update(age=32, is_active=False)

# Convert to MongoDB document
doc = user.model_dump_doc()
print(doc)  # {'_id': ObjectId(...), 'name': 'Alice Smith', ...}

# Parse from MongoDB document
raw_doc = {
    '_id': ObjectId('...'),
    'name': 'Bob Jones',
    'email': 'bob@example.com',
    'age': 25,
    'created_at': datetime.utcnow(),
    'is_active': True
}
user = User.model_validate_doc(raw_doc)

Model with Relationships

from odmantic import Model, Reference, ObjectId

class Author(Model):
    name: str
    email: str

class Book(Model):
    title: str
    author_id: ObjectId = Reference()
    published_year: int
    
    # You can define a property to load the related author
    # (This would require custom implementation with the engine)

# Usage
author = Author(name="Jane Doe", email="jane@example.com")
book = Book(
    title="Python Patterns",
    author_id=author.id,
    published_year=2023
)

Model Validation

from pydantic import validator, field_validator

class User(Model):
    name: str
    email: str
    age: int
    
    @field_validator('email')
    @classmethod
    def validate_email(cls, v):
        if '@' not in v:
            raise ValueError('Invalid email format')
        return v.lower()
    
    @field_validator('name')
    @classmethod
    def validate_name(cls, v):
        if len(v.strip()) < 2:
            raise ValueError('Name must be at least 2 characters')
        return v.strip().title()

# This will raise validation errors for invalid data
try:
    user = User(name="A", email="invalid", age=25)
except ValidationError as e:
    print(e.errors())

Model with Custom Primary Key

from odmantic import Model, Field
import uuid

class CustomIdModel(Model):
    custom_id: str = Field(primary_field=True, default_factory=lambda: str(uuid.uuid4()))
    name: str
    value: int

# The custom_id field will be stored as _id in MongoDB
model = CustomIdModel(name="test", value=42)
print(model.custom_id)  # Auto-generated UUID string

Model Configuration Options

from odmantic import Model
from odmantic.config import ODMConfigDict

class ConfiguredModel(Model):
    name: str
    secret_field: str
    
    model_config = ODMConfigDict(
        # MongoDB collection name
        collection="my_collection",
        
        # Extra fields behavior: "allow", "forbid", "ignore"
        extra="forbid",
        
        # Validate field assignments
        validate_assignment=True,
        
        # Use enum values instead of names
        use_enum_values=True,
        
        # Allow population by field name and alias
        populate_by_name=True
    )

Install with Tessl CLI

npx tessl i tessl/pypi-odmantic

docs

bson-types.md

engines.md

fields.md

index.md

indexes.md

models.md

queries.md

sessions.md

tile.json