From 0b58f4fe497010600af615d02f6b123d38ee6b30 Mon Sep 17 00:00:00 2001 From: Micheal Taylor Date: Sun, 31 May 2020 16:05:01 -0600 Subject: [PATCH] [WIP] Add pydantic model creation method to Gino Model Adds a class method 'get_pydantic_model' to the base Model class that introspects the class to provide a pydantic model. --- src/gino/declarative.py | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/gino/declarative.py b/src/gino/declarative.py index 9f349cd3..178d54e8 100644 --- a/src/gino/declarative.py +++ b/src/gino/declarative.py @@ -1,5 +1,6 @@ import collections +from pydantic import create_model import sqlalchemy as sa from sqlalchemy.exc import InvalidRequestError @@ -361,6 +362,65 @@ def _init_table(cls, sub_cls): ) return rv + @classmethod + def get_pydantic_model(cls): + """Return a pydantic model from the GINO model definition. + + Will check for an __exclude__ property on the class to identify + class attributes that should be excluded from the pydantic model + generation. + + + Example: + + class User(db.Model): + __tablename__ = 'users' + + name = db.Column(db.String()) + ​ + User = + PUser = User.get_pydantic_model() + indent=2 + print(PUser.schema_json(indent=2)) + { + "title": "User", + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string" + } + }, + "required": [ + "name" + ] + } + """ + + keys = [str(key) for key in cls.__dict__.keys()] + # Assumption that may not be valid, but don't look at ones with _ in them. + valid_keys = [key for key in keys if not key.startswith('_')] + + # Allow exclusions of model attributes from the pydantic model. + if hasattr(cls, '__excluded__'): + valid_keys = [key for key in valid_keys if key not in cls.__excluded__] + + # This may be unique to GINO where the python type is on a column, but + # It would be easy enough to make a reference table for this rather than + # pulling it directly from the model column. + field_definitions = {} + for key in valid_keys: + col = getattr(cls, key) + col_type = col.type.python_type + # Don't forget ellipses after this, or pydantic won't create + # the schema and validators properly. + field_definitions[key] = (col.type.python_type,...) + + # Create our pydantic model + pmodel = create_model(cls.__name__, **field_definitions) + + return pmodel + def declarative_base(metadata, model_classes=(Model,), name="Model"): """Create a base GINO model class for declarative table definition.