Skip to content

Commit

Permalink
first step of creating nested pydantic models in metaclass
Browse files Browse the repository at this point in the history
without running code because database was changed and need alembic first
  • Loading branch information
mrtedn21 committed Sep 14, 2023
1 parent b3f91ee commit 12d1459
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 14 deletions.
29 changes: 23 additions & 6 deletions database.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
async_sessionmaker,
create_async_engine,
)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, InstrumentedAttribute

from openapi import add_openapi_schema

Expand All @@ -28,6 +28,7 @@ class NewModel(SomeSqlAlchemyModel, metaclass=SqlAlchemyToPydantic):
fields = '__all__'
fields attribute can be on of:
* '__all__' - means that pydantic model will be with all
fields of alchemy model
* '__without_pk__' - means will be all fields instead of pk
Expand Down Expand Up @@ -55,12 +56,28 @@ def __new__(cls, name, bases, fields):
elif defined_fields == '__without_pk__':
defined_fields = tuple(set(origin_model_field_names) - {'pk'})

# Create simple fields, of type int, str, etc.
result_fields = {
field_name:
(getattr(origin_model, field_name).type.python_type, ...)
field_name: (
getattr(origin_model, field_name).type.python_type, ...
)
for field_name in defined_fields
if field_name in origin_model_field_names
if field_name in origin_model_field_names and
# if alchemy field has 'type' property,
# it means the field is simple, int, str, etc.
hasattr(getattr(origin_model, field_name), 'type')
}

# Create complex fields, of pydantic models,
# for creating nested pydantic models
result_fields.update({
field_name: (fields[field_name], ...)
for field_name in defined_fields
if field_name in origin_model_field_names and
# if alchemy field hasn't 'type' property, it means the field is relation
not hasattr(getattr(origin_model, field_name), 'type')
})

result_model = create_model(
name,
**result_fields,
Expand All @@ -82,8 +99,8 @@ def is_secondary_relation(model, attribute_name):
therefore I say that it is secondary relation
And this function separate primary relation in model from secondary.
The function return True only if attribute from second arg is
secondary relationship."""
The function return True only if attribute from attribute_name
argument is secondary relationship."""
attribute = getattr(model, attribute_name)

try:
Expand Down
16 changes: 8 additions & 8 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ def get_dict_from_orm_object(some_object):
return result_data


#class CountryGetModel(CountryOrm, metaclass=SqlAlchemyToPydantic):
# fields = '__all__'
#
#
#class CountryCreateModel(CountryOrm, metaclass=SqlAlchemyToPydantic):
# fields = '__without_pk__'
class CountryGetModel(CountryOrm, metaclass=SqlAlchemyToPydantic):
fields = '__all__'


class CountryCreateModel(CountryOrm, metaclass=SqlAlchemyToPydantic):
fields = '__without_pk__'


class CityGetModel(CityOrm, metaclass=SqlAlchemyToPydantic):
fields = '__all__'
#country = CountryGetModel
country = CountryGetModel


class CityCreateModel(CityOrm, metaclass=SqlAlchemyToPydantic):
fields = '__without_pk__'
#country = CountryCreateModel
country = CountryCreateModel


class UserGetModel(UserOrm, metaclass=SqlAlchemyToPydantic):
Expand Down

0 comments on commit 12d1459

Please sign in to comment.