Create Pydantic model from Huge SQLModel #1108
Unanswered
mmmcorpsvit
asked this question in
Questions
Replies: 2 comments 1 reply
-
my current solution, but maybe present more official way? I adapt for SQLModel converting from tortoise-orm package from typing import Type, Tuple, Dict, Any, Optional, List
from pydantic import BaseModel, Field, create_model, field_validator
from sqlmodel import SQLModel, Field as SQLField, Relationship
# SQLModel Mixins
class TimestampMixin(SQLModel):
created_at: Optional[str] = SQLField(default=None)
updated_at: Optional[str] = SQLField(default=None)
class IdentifiableMixin(SQLModel):
id: int = SQLField(default=None, primary_key=True)
# Pydantic Mixins
class TimestampMixinPydantic(BaseModel):
created_at: Optional[str] = None
updated_at: Optional[str] = None
@field_validator("created_at", "updated_at", mode="before")
def validate_datetime(cls, v):
# Example validation logic
if v and len(v) != 19: # Example check for datetime format
raise ValueError(f"Invalid datetime format: {v}")
return v
class IdentifiableMixinPydantic(BaseModel):
id: int
# Function to create Pydantic models from SQLModel models
def pydantic_model_creator(
cls: Type[SQLModel],
*,
name: Optional[str] = None,
exclude: Tuple[str, ...] = (),
include: Tuple[str, ...] = (),
computed: Tuple[str, ...] = (),
optional: Tuple[str, ...] = (),
sort_alphabetically: Optional[bool] = None,
exclude_readonly: bool = False,
model_config: Optional[dict] = None,
validators: Optional[Dict[str, Any]] = None,
module: str = __name__,
) -> Type[BaseModel]:
"""
Function to build a Pydantic Model off SQLModel Model.
"""
fqname = cls.__module__ + "." + cls.__qualname__
def get_name() -> str:
is_default = (
exclude == ()
and include == ()
and computed == ()
and sort_alphabetically is None
)
hashval = f"{fqname};{exclude};{include};{computed}:{sort_alphabetically}"
postfix = f":{hashval[:6]}" if not is_default else ""
return fqname + postfix
_name = name or get_name()
# Get SQLModel fields
properties: Dict[str, Any] = {}
annotations = cls.__annotations__
for fname, field_type in annotations.items():
if (include and fname not in include) or fname in exclude:
continue
# Access the field information
# field = cls.__fields__.get(fname)
field = cls.model_fields.get(fname)
if not field:
continue
field_default = field.default
is_optional_field = fname in optional
# Handle relationships
if isinstance(field_type, type) and issubclass(field_type, SQLModel):
submodel = pydantic_model_creator(
field_type,
exclude=tuple(f"{fname}.{ex}" for ex in exclude),
include=tuple(f"{fname}.{inc}" for inc in include),
computed=computed,
sort_alphabetically=sort_alphabetically,
exclude_readonly=exclude_readonly,
model_config=model_config,
validators=validators,
)
properties[fname] = Optional[submodel] if field.default is None else List[submodel]
continue
# Handle computed fields
if fname in computed:
func = lambda: f"Computed {fname}"
properties[fname] = Field(default=func, description=f"Computed field: {fname}")
continue
# Handle regular fields
if field_default is None and is_optional_field:
field_default = None
ptype = field_type
if is_optional_field or field_default is not None:
ptype = Optional[ptype]
if not (exclude_readonly and getattr(field, "readonly", False)):
properties[fname] = (ptype, Field(default=field_default))
if sort_alphabetically:
properties = dict(sorted(properties.items()))
# Create Pydantic model
pconfig = model_config or {}
if "title" not in pconfig:
pconfig["title"] = name or cls.__name__
if "extra" not in pconfig:
pconfig["extra"] = "forbid"
model = create_model(
_name,
__base__=BaseModel,
__module__=module,
**properties,
)
# Apply custom validators if provided
if validators:
for field_name, validator_fn in validators.items():
if hasattr(model, field_name):
setattr(model, field_name, field_validator(field_name, mode="before")(validator_fn))
model.__doc__ = cls.__doc__
return model
# Define related SQLModel classes
class CarType(TimestampMixin, IdentifiableMixin, SQLModel, table=True):
name: str
description: Optional[str]
cars: List["Car"] = Relationship(back_populates="car_type")
class Car(TimestampMixin, IdentifiableMixin, SQLModel, table=True):
make: str
model: str
year: int
color: str
car_type_id: int = SQLField(foreign_key="cartype.id")
car_type: Optional[CarType] = Relationship(back_populates="cars")
# Create Pydantic models from SQLModel
CarPydanticModel = pydantic_model_creator(
Car,
name="CarPydantic",
exclude=("car_type_id",), # Exclude field
include=("make", "model", "year", "color"), # Include fields
computed=("full_name",), # Add computed field
optional=("color",), # Mark field as optional
sort_alphabetically=True,
exclude_readonly=True,
model_config={"title": "Car Model"},
validators={
"year": lambda v: v if v > 1900 else 1900 # Use field_validator
}
)
CarTypePydanticModel = pydantic_model_creator(
CarType,
name="CarTypePydantic",
exclude=("description",), # Exclude field
include=("name",), # Include fields
sort_alphabetically=True,
model_config={"title": "Car Type Model"}
)
# Example usage
car_instance = CarPydanticModel(
id=1,
make="Toyota",
model="Camry",
year=2022,
color="Blue",
car_type=CarTypePydanticModel(id=1, name="Sedan")
)
print(car_instance) |
Beta Was this translation helpful? Give feedback.
0 replies
-
Can't your sqlmodel class be used directly? |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
First Check
Commit to Help
Example Code
Description
I have huge main SQLModel class - Lot, with many nested models (LotSaleTitleType , AuctionSeller ) - this models too have nested model etc...
what a best way to create Pydantic model with include/exclude?
for example i need ResponseModel for FastAPI Endpoint:
how i can declare LotShortSchema (just few fields like id, vin etc...) and LotSchema (without few fields) without copy paste/pain. And need include/exclude fields from nested models. Are possible for example exclude from all nested models field 'slug' if present ?
Operating System
Windows
Operating System Details
No response
SQLModel Version
0.0.22
Python Version
3.11
Additional Context
No response
Beta Was this translation helpful? Give feedback.
All reactions