@@ -273,7 +273,9 @@ def __new__(
273273 key : pydantic_kwargs .pop (key )
274274 for key in pydantic_kwargs .keys () & allowed_config_kwargs
275275 }
276- config_table = getattr (class_dict .get ("Config" , object ()), "table" , False ) or kwargs .get ("table" , False )
276+ config_table = getattr (
277+ class_dict .get ("Config" , object ()), "table" , False
278+ ) or kwargs .get ("table" , False )
277279 # If we have a table, we need to have defaults for all fields
278280 # Pydantic v2 sets a __pydantic_core_schema__ which is very hard to change. Changing the fields does not do anything
279281 if config_table is True :
@@ -282,7 +284,12 @@ def __new__(
282284 if value is PydanticUndefined :
283285 dict_used [key ] = None
284286 elif isinstance (value , FieldInfo ):
285- if value .default is PydanticUndefined and value .default_factory is None :
287+ if (
288+ value .default in (PydanticUndefined , Ellipsis )
289+ ) and value .default_factory is None :
290+ value .original_default = (
291+ value .default
292+ ) # So we can check for nullable
286293 value .default = None
287294
288295 new_cls : Type ["SQLModelMetaclass" ] = super ().__new__ (
@@ -496,6 +503,7 @@ def get_column_from_field(field: FieldInfo) -> Column: # type: ignore
496503class_registry = weakref .WeakValueDictionary () # type: ignore
497504
498505default_registry = registry ()
506+ _TSQLModel = TypeVar ("_TSQLModel" , bound = "SQLModel" )
499507
500508
501509class SQLModel (BaseModel , metaclass = SQLModelMetaclass , registry = default_registry ):
@@ -549,12 +557,28 @@ def __tablename__(cls) -> str:
549557 return cls .__name__ .lower ()
550558
551559 @classmethod
552- def model_validate (cls , * args , ** kwargs ):
553- return super ().model_validate (* args , ** kwargs )
560+ def model_validate (
561+ cls : type [_TSQLModel ],
562+ obj : Any ,
563+ * ,
564+ strict : bool | None = None ,
565+ from_attributes : bool | None = None ,
566+ context : dict [str , Any ] | None = None ,
567+ ) -> _TSQLModel :
568+ # Somehow model validate doesn't call __init__ so it would remove our init logic
569+ validated = super ().model_validate (
570+ obj , strict = strict , from_attributes = from_attributes , context = context
571+ )
572+ return cls (** {key : value for key , value in validated })
554573
555574
556575def _is_field_noneable (field : FieldInfo ) -> bool :
576+ if getattr (field , "nullable" , PydanticUndefined ) is not PydanticUndefined :
577+ return field .nullable
557578 if not field .is_required ():
579+ default = getattr (field , "original_default" , field .default )
580+ if default is PydanticUndefined :
581+ return False
558582 if field .annotation is None or field .annotation is NoneType :
559583 return True
560584 if get_origin (field .annotation ) is Union :
0 commit comments