- Modify
BaseSettings
imports:
- Any project files using pydantic's
BaseSettings
ENV config model must shift their import target topydantic_settings
from pydantic import BaseSettings
becomes
from pydantic_settings import BaseSettings
- Replace
@app.on_event("startup")
and@app.on_event("shutdown")
withlifespan
context manager.
- Upgrade your
main.py
file:
from fastapi import FastAPI
from myproject.router import application as application_router
app = FastAPI(title="My Project", version="0.0.0")
@app.on_event("startup")
async def bootstrap():
app.include_router(application_router)
@app.on_event("shudtown")
async def shutdown():
pass
becomes
from contextlib import asynccontextmanager
from fastapi import FastAPI
from myproject.router import application as application_router
async def bootstrap(application: FastAPI):
application.include_router(application_router)
async def shutdown():
pass
@asynccontextmanager
async def lifespan(application: FastAPI):
await bootstrap(application)
yield
await shutdown()
app = FastAPI(
title="My Project", version="0.0.0", lifespan=lifespan
)
- (Optional) As of December 2023, there is a known bug with
sqlmodel
0.0.14 where type checking on TABLE models will complain, but will still work.
- For any models that have a corresponding database table by using
table=True
in the class declaration, modify the declaration to ignore class type checking:
class Widget(CruddyModel, table=True):
pass
becomes
class Widget(CruddyModel, table=True): # type: ignore
pass
- Schema
example
attribute has been moved to pluralexamples
. Modify any use ofschema_extra
which declaresexample
attribute.
- For any models that leverage
schema_extra={"example": "some value}
:
class Widget(CruddyModel):
name: str = Field(schema_extra={"example": "Widget Name"})
becomes
class Widget(CruddyModel):
name: str = Field(
schema_extra={
"json_schema_extra": {
"example": "Widget Name"
}
}
)
UTCDateTime
has been removed due topydantic
andsqlalchemy
incompatibility with this custom type.
- Modify any model fields depending on cruddy's
UTCDateTime
to leverage the newfield_validator
namedvalidate_utc_datetime
:
from sqlmodel import Field, Column, DateTime
from fastapi_cruddy_framework import CruddyModel, UTCDateTime
class Widget(CruddyModel):
event_date: UTCDateTime | None = Field(
sa_column=Column(DateTime(timezone=True), nullable=True)
)
becomes
from typing import Any
from datetime import datetime
from pydantic import field_validator
from sqlmodel import Field, Column, DateTime
from fastapi_cruddy_framework import CruddyModel, validate_utc_datetime
class Widget(CruddyModel):
event_date: datetime | None = Field(
default=None,
sa_column=Column(
DateTime(timezone=True),
nullable=True,
index=True,
default=None,
),
)
@field_validator("event_date", mode="before")
@classmethod
def validate_event_date(cls, v: Any) -> datetime | None:
return validate_utc_datetime(v, allow_none=True)
pydantic
2+, and thereforesqlmodel
, is more strict withOptional
fields.
- Modify any models with
Optional
fields to conform topydantic
verison 2+'s stricter possible empty value declarations:
from sqlmodel import Field
from fastapi_cruddy_framework import CruddyModel
# Style 1
class Widget(CruddyModel):
name: str | None = Field()
# Style 2
class Foo(CruddyModel):
name: str | None
becomes
from sqlmodel import Field
from fastapi_cruddy_framework import CruddyModel
# Style 1
class Widget(CruddyModel):
name: str | None = Field(default=None)
# Style 2
class Foo(CruddyModel):
name: str | None = None
- (Optional) Take advantage of new checkers and validators that ship with
fastapi-cruddy-framework
, courtesy of the validator-collection. For additional documentation on what is available, see that project's README. This change also provides an alternative to the pydanticEmailStr
type which is no longer available for use inpydantic
2.0 +sqlalchemy
2.0.
- Modify any models that might now use
validator-collection
via importing cruddy's exports:
# various imports ...
class Widget(CruddyModel):
some_field: str | None = Field(default=None)
@field_validator("some_field", mode="before")
@classmethod
def validate_some_field(cls, v: str) -> str | None:
# ... some custom e-mail address validation logic
return v
becomes
# various imports ...
from fastapi_cruddy_framework import field_checkers, field_validators, field_errors
# field_validators = validators
# field_checkers = checkers
# field_errors = errors
class Widget(CruddyModel):
some_field: str | None = Field(default=None)
@field_validator("some_field", mode="before")
@classmethod
def validate_some_field(cls, v: str) -> str | None:
return field_validators.email(v)
pydantic
2.0+ replacesrecord.dict()
withrecord.model_dump()
.
- Modify all calls to
.dict()
by replacing with.model_dump()
:
record_dict = record.dict()
becomes
record_dict = record.model_dump()
pydantic
2.0+ moves the defaultUndefined
field, and all otherfields
, topydantic_core
.
- Modify all references to
Undefined
or other fields:
from pydantic.fields import Undefined
becomes
from pydantic_core import PydanticUndefined as Undefined
This applies to all custom pydantic fields
- Model class level fields are no longer accessed via the private attribute
__fields__
.
- Modify all references to
__fields__
:
my_model.__fields__
becomes
my_model.model_fields
- Cruddy's
BulkDTO
type alters thedata
attribute's primary type, in accordance with the new return value fromsqlalchemy
2.0+.
- Modify any code directly using a
BulkDTO
object to change type dependence:
class BulkDTO(CruddyGenericModel):
total_pages: int
total_records: int
limit: int
page: int
data: list[Row]
becomes
class BulkDTO(CruddyGenericModel):
total_pages: int
total_records: int
limit: int
page: int
data: Sequence[Row]
- As of December 2023,
sqlmodel
does not supportlambda
functions when declaring ansa_column
Field
argument. As a result,created_at
andupdated_at
fields have been separated from core cruddy models and isolated into a functional class generator mixin. This allows framework users to achieve the same effect without creatingsqlalchemy
errors because multiple models are trying to share the sameColumn
instance.
- Modify any code where a
table=true
model expects the normal cruddycreated_at
andupdated_at
timestamping functionality:
from fastapi_cruddy_framework import CruddyIntIDModel, CruddyUUIDModel
from sqlmodel import Field
class Widget(CruddyUUIDModel, table=True):
name: str = Field(nullable=False, index=True)
class Foo(CruddyIntIDModel, table=True):
name: str = Field(nullable=False, index=True)
becomes
# The "type: ignore" comments are for migration note 3, ABOVE ^
from fastapi_cruddy_framework import CruddyIntIDModel, CruddyUUIDModel, CruddyCreatedUpdatedMixin
from sqlmodel import Field
class Widget(CruddyCreatedUpdatedMixin(), CruddyUUIDModel, table=True): # type: ignore
name: str = Field(nullable=False, index=True)
class Foo(CruddyCreatedUpdatedMixin(), CruddyIntIDModel, table=True): # type: ignore
name: str = Field(nullable=False, index=True)