diff --git a/docs/examples/models_orm_mode_reserved_name.py b/docs/examples/models_orm_mode_reserved_name.py new file mode 100644 index 0000000..dafc895 --- /dev/null +++ b/docs/examples/models_orm_mode_reserved_name.py @@ -0,0 +1,27 @@ +import typing + +from pydantic import BaseModel, Field +import sqlalchemy as sa +from sqlalchemy.ext.declarative import declarative_base + +class MyModel(BaseModel): + metadata: typing.Dict[str, str] = Field(alias='metadata_') + + class Config: + orm_mode = True + +BaseModel = declarative_base() + +class SQLModel(BaseModel): + + __tablename__ = 'my_table' + id = sa.Column('id', sa.Integer, primary_key=True) + # 'metadata' is reserved by SQLAlchemy, hence the '_' + metadata_ = sa.Column('metadata', sa.JSON) + +sql_model = SQLModel(metadata_={'key': 'val'}, id=1) + +pydantic_model = MyModel.from_orm(sql_model) + +print(pydantic_model.dict()) +print(pydantic_model.dict(by_alias=True)) diff --git a/docs/usage/models.md b/docs/usage/models.md index 7ca9ecf..bb2c866 100644 --- a/docs/usage/models.md +++ b/docs/usage/models.md @@ -132,6 +132,22 @@ The example here uses SQLAlchemy, but the same approach should work for any ORM. ``` _(This script is complete, it should run "as is")_ +### Reserved names + +You may want to name a Column after a reserved SQLAlchemy field. In that case, Field aliases will be +convenient: + +```py +{!.tmp_examples/models_orm_mode_reserved_name.py!} +``` +_(This script is complete, it should run "as is")_ + +!!! note + The example above works because aliases have priority over field names for + field population. Accessing `SQLModel`'s `metadata` attribute would lead to a `ValidationError`. + +### Recursive ORM models + ORM instances will be parsed with `from_orm` recursively as well as at the top level. Here a vanilla class is used to demonstrate the principle, but any ORM class could be used instead.