Releases: collerek/ormar
Fixes for prefetch related and saving related
0.20.1
✨ Breaking changes
- Note that this is the first non-beta release of ormar with support for Pydantic v2. Check release notes for 0.20.0 and https://collerek.github.io/ormar/0.20.0b1/migration/
🐛 Fixes
- Fix merging same target models when using
select_related
withprefetch_related
#906 - Fix saving related with pk only models #812
- Fix adding the same relation multiple times corrupting relation cache #1335
✨ Features
💬 Other
- Some docs fixes by @Chaoyingz, thanks!
BETA - Support for pydantic v2
BETA
0.20.0
You can find updated documentation at: https://collerek.github.io/ormar/0.20.0b1/
✨ Breaking changes
-
ormar
Model configurationInstead of defining a
Meta
class now each of the ormar models require an ormar_config parameter that is an instance of theOrmarConfig
class.
Note that the attribute must be namedormar_config
and be an instance of the config class.import databases import ormar import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() # ormar < 0.20 class Album(ormar.Model): class Meta: database = database metadata = metadata tablename = "albums" id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) favorite: bool = ormar.Boolean(default=False) # ormar >= 0.20 class AlbumV20(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, tablename="albums_v20" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) favorite: bool = ormar.Boolean(default=False)
-
OrmarConfig
api/ parametersThe
ormar_config
expose the same set of settings asMeta
class used to provide.
That means that you can use any of the following parameters initializing the config:metadata: Optional[sqlalchemy.MetaData] database: Optional[databases.Database] engine: Optional[sqlalchemy.engine.Engine] tablename: Optional[str] order_by: Optional[List[str]] abstract: bool exclude_parent_fields: Optional[List[str]] queryset_class: Type[QuerySet] extra: Extra constraints: Optional[List[ColumnCollectionConstraint]]
-
BaseMeta
equivalent - best practiceNote that to reduce the duplication of code and ease of development it's still recommended to create a base config and provide each of the models with a copy.
OrmarConfig provides a convenientcopy
method for that purpose.The
copy
method accepts the same parameters asOrmarConfig
init, so you can overwrite if needed, but by default it will return already existing attributes, except for:tablename
,order_by
andconstraints
which by default are cleared.import databases import ormar import sqlalchemy base_ormar_config = ormar.OrmarConfig( database=databases.Database("sqlite:///db.sqlite"), metadata=sqlalchemy.MetaData() ) class AlbumV20(ormar.Model): ormar_config = base_ormar_config.copy( tablename="albums_v20" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) class TrackV20(ormar.Model): ormar_config = base_ormar_config.copy( tablename="tracks_v20" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100)
-
choices
Field parameter is no longer supported.Before version 0.20 you could provide
choices
parameter to any existing ormar Field to limit the accepted values.
This functionality was dropped, and you should useormar.Enum
field that was designed for this purpose.
If you want to keep the database field type (i.e. an Integer field) you can always write a custom validator.import databases import ormar import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() # ormar < 0.20 class Artist(ormar.Model): class Meta: database = database metadata = metadata id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) country: str = ormar.String(default=False, max_length=50, choices=["UK", "US", "Vietnam", "Colombia"]) # ormar >= 0.20 from enum import Enum class Country(str, Enum): UK = "UK" US = "US" VIETNAM = "Vietnam" COLOMBIA = "Colombia" class ArtistV20(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, tablename="artists_v20" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) country: Country = ormar.Enum(enum_class=Country)
-
pydantic_only
Field parameter is no longer supportedpydantic_only
fields were already deprecated and are removed in v 0.20. Ormar allows defining pydantic fields as in ordinary pydantic model.import databases import ormar import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() # ormar < 0.20 class Dish(ormar.Model): class Meta: database = database metadata = metadata tablename = "dishes" id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) cook: str = ormar.String(max_length=40, pydantic_only=True, default="sam") # ormar >= 0.20 class DishV20(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, tablename="dishes_v20" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) cook: str = "sam" # this is normal pydantic field
-
property_field
decorator is no longer supportedproperty_field
decorator was used to provide a way to pass calculated fields that were included in dictionary/ serialized json representation of the model.
Version 2.X of pydantic introduced such a possibility, so you should now switch to the one native to the pydantic.import databases import ormar import sqlalchemy import pydantic database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() # ormar < 0.20 class Employee(ormar.Model): class Meta: database = database metadata = metadata id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=100) last_name: str = ormar.String(max_length=100) @ormar.property_field() def full_name(self) -> str: return f"{self.first_name} {self.last_name}" # ormar >= 0.20 class EmployeeV20(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, ) id: int = ormar.Integer(primary_key=True) first_name: str = ormar.String(max_length=100) last_name: str = ormar.String(max_length=100) @pydantic.computed_field() def full_name(self) -> str: return f"{self.first_name} {self.last_name}"
-
Deprecated methods
All methods listed below are deprecated and will be removed in version 0.30 of
ormar
.dict()
becomes themodel_dump()
import databases import ormar import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() class Album(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, tablename="albums" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) favorite: bool = ormar.Boolean(default=False) album = Album(name="Dark Side of the Moon") # ormar < 0.20 album_dict = album.dict() # ormar >= 0.20 new_album_dict = album.model_dump()
Note that parameters remain the same i.e.
include
,exclude
etc.-
json()
becomes themodel_dump_json()
import databases import ormar import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() class Album(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, tablename="albums" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) favorite: bool = ormar.Boolean(default=False) album = Album(name="Dark Side of the Moon") # ormar < 0.20 album_json= album.json() # ormar >= 0.20 new_album_dict = album.model_dump_json()
Note that parameters remain the same i.e.
include
,exclude
etc. -
construct()
becomes themodel_construct()
import databases import ormar import sqlalchemy database = databases.Database("sqlite:///db.sqlite") metadata = sqlalchemy.MetaData() class Album(ormar.Model): ormar_config = ormar.OrmarConfig( database=database, metadata=metadata, tablename="albums" ) id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=100) favorite: bool = ormar.Boolean(default=False) params = { "n...
Bump fastapi and python
Performance improvements
0.12.1
✨ Features
- Massive performance improvements in the area of loading the models due to recursive loads and caching of the models and related models. (by @erichaydel - thanks!) #853
💬 Internals
- Benchmarks for comparing the performance effect of implemented changes in regard of trends (again, by @erichaydel - thanks!) #853
Force save in upset and bug fixes
0.12.0
✨ Breaking Changes
Queryset.bulk_create
will now raiseModelListEmptyError
on empty list of models (by @ponytailer - thanks!) #853
✨ Features
Model.upsert()
now handles a flag__force_save__
:bool
that allow upserting the models regardless of the fact if they have primary key set or not.
Note that setting this flag will cause two queries for each upserted model ->get
to check if model exists and laterupdate/insert
accordingly. #889
🐛 Fixes
- Fix for empty relations breaking
construct
method (by @Abdeldjalil-H - thanks!) #870 - Fix save related not saving models with already set pks (including uuid) #885
- Fix for wrong relations exclusions depending on the order of exclusions #779
- Fix
property_fields
not being inherited properly #774
CheckColumn constraint, ReferentialAction and bug fixes
0.11.3
✨ Features
- Document
onupdate
andondelete
referential actions inForeignKey
and provideReferentialAction
enum to specify the behavior of the relationship (by @SepehrBazyar - thanks!) #724 - Add
CheckColumn
to supported constraints in models Meta (by @SepehrBazyar - thanks!) #729
🐛 Fixes
- Fix limiting query result to 0 should return empty list (by @SepehrBazyar - thanks!) #766
💬 Other
- Add dark mode to docs (by @SepehrBazyar - thanks!) #717
- Update aiomysql dependency #778
Bug fixes and packaging fix
Fix deepcopy issues for pydantic >=1.9
Add python 3.10 support, drop python 3.6 and minor fixes/changes
0.11.0
✨ Breaking Changes
- Dropped support for python 3.6
Queryset.get_or_create
returns now a tuple with model and bool value indicating if the model was created (by @mojixcoder - thanks!) #554Queryset.count()
now counts the number of distinct parent model rows by default, counting all rows is possible by settingdistinct=False
(by @erichaydel - thanks) #588
✨ Features
- Added support for python 3.10
🐛 Fixes
Add plugable queryset_class, enhance IndexColumns and bug fixes
0.10.25
✨ Features
- Add
queryset_class
option toModel.Meta
that allows you to easily swapQuerySet
for your Model (by @ponytailer - thanks!) #538 - Allow passing extra
kwargs
toIndexColumns
that will be passed to sqlalchemyIndex
(by @zevisert - thanks) #575
🐛 Fixes
- Fix nullable setting on
JSON
fields #529 - Fix bytes/str mismatch in bulk operations when using orjson instead of json (by @ponytailer - thanks!) #538