migrating_versions.md
April 3, 2024 ยท View on GitHub
Migration Guide
fastapi-cruddy-framework 0.x.x -> 1.x.x
Dependency Guides:
Code Mods Required:
- Modify
BaseSettingsimports:
- Any project files using pydantic's
BaseSettingsENV 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")withlifespancontext manager.
- Upgrade your
main.pyfile:
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
sqlmodel0.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=Truein 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
exampleattribute has been moved to pluralexamples. Modify any use ofschema_extrawhich declaresexampleattribute.
- 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"
}
}
)
UTCDateTimehas been removed due topydanticandsqlalchemyincompatibility with this custom type.
- Modify any model fields depending on cruddy's
UTCDateTimeto leverage the newfield_validatornamedvalidate_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)
pydantic2+, and thereforesqlmodel, is more strict withOptionalfields.
- Modify any models with
Optionalfields to conform topydanticverison 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 pydanticEmailStrtype which is no longer available for use inpydantic2.0 +sqlalchemy2.0.
- Modify any models that might now use
validator-collectionvia 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)
pydantic2.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()
pydantic2.0+ moves the defaultUndefinedfield, and all otherfields, topydantic_core.
- Modify all references to
Undefinedor 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
BulkDTOtype alters thedataattribute's primary type, in accordance with the new return value fromsqlalchemy2.0+.
- Modify any code directly using a
BulkDTOobject 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,
sqlmodeldoes not supportlambdafunctions when declaring ansa_columnFieldargument. As a result,created_atandupdated_atfields 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 creatingsqlalchemyerrors because multiple models are trying to share the sameColumninstance.
- Modify any code where a
table=truemodel expects the normal cruddycreated_atandupdated_attimestamping 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)