33import ipaddress
44import uuid
55import weakref
6+ from dataclasses import dataclass
67from datetime import date , datetime , time , timedelta
78from decimal import Decimal
89from enum import Enum
@@ -347,6 +348,38 @@ def Field(
347348) -> Any : ...
348349
349350
351+ @dataclass
352+ class FieldInfoMetadata :
353+ primary_key : Union [bool , UndefinedType ] = Undefined
354+ nullable : Union [bool , UndefinedType ] = Undefined
355+ foreign_key : Any = Undefined
356+ ondelete : Union [OnDeleteType , UndefinedType ] = Undefined
357+ unique : Union [bool , UndefinedType ] = Undefined
358+ index : Union [bool , UndefinedType ] = Undefined
359+ sa_type : Union [Type [Any ], UndefinedType ] = Undefined
360+ sa_column : Union [Column [Any ], UndefinedType ] = Undefined
361+ sa_column_args : Union [Sequence [Any ], UndefinedType ] = Undefined
362+ sa_column_kwargs : Union [Mapping [str , Any ], UndefinedType ] = Undefined
363+
364+
365+ def _get_sqlmodel_field_metadata (field_info : Any ) -> Optional [FieldInfoMetadata ]:
366+ metadata_items = getattr (field_info , "metadata" , None )
367+ if metadata_items :
368+ for meta in metadata_items :
369+ if isinstance (meta , FieldInfoMetadata ):
370+ return meta
371+ return None
372+
373+
374+ def _get_sqlmodel_field_value (
375+ field_info : Any , attribute : str , default : Any = Undefined
376+ ) -> Any :
377+ metadata = _get_sqlmodel_field_metadata (field_info )
378+ if metadata is not None and hasattr (metadata , attribute ):
379+ return getattr (metadata , attribute )
380+ return getattr (field_info , attribute , default )
381+
382+
350383def Field (
351384 default : Any = Undefined ,
352385 * ,
@@ -427,6 +460,20 @@ def Field(
427460 sa_column_kwargs = sa_column_kwargs ,
428461 ** current_schema_extra ,
429462 )
463+ field_metadata = FieldInfoMetadata (
464+ primary_key = primary_key ,
465+ nullable = nullable ,
466+ foreign_key = foreign_key ,
467+ ondelete = ondelete ,
468+ unique = unique ,
469+ index = index ,
470+ sa_type = sa_type ,
471+ sa_column = sa_column ,
472+ sa_column_args = sa_column_args ,
473+ sa_column_kwargs = sa_column_kwargs ,
474+ )
475+ if hasattr (field_info , "metadata" ):
476+ field_info .metadata .append (field_metadata ) # type: ignore[attr-defined]
430477 post_init_field_info (field_info )
431478 return field_info
432479
@@ -651,7 +698,7 @@ def get_sqlalchemy_type(field: Any) -> Any:
651698 field_info = field
652699 else :
653700 field_info = field .field_info
654- sa_type = getattr (field_info , "sa_type" , Undefined ) # noqa: B009
701+ sa_type = _get_sqlmodel_field_value (field_info , "sa_type" , Undefined )
655702 if sa_type is not Undefined :
656703 return sa_type
657704
@@ -708,39 +755,39 @@ def get_column_from_field(field: Any) -> Column: # type: ignore
708755 field_info = field
709756 else :
710757 field_info = field .field_info
711- sa_column = getattr (field_info , "sa_column" , Undefined )
758+ sa_column = _get_sqlmodel_field_value (field_info , "sa_column" , Undefined )
712759 if isinstance (sa_column , Column ):
713760 return sa_column
714761 sa_type = get_sqlalchemy_type (field )
715- primary_key = getattr (field_info , "primary_key" , Undefined )
762+ primary_key = _get_sqlmodel_field_value (field_info , "primary_key" , Undefined )
716763 if primary_key is Undefined :
717764 primary_key = False
718- index = getattr (field_info , "index" , Undefined )
765+ index = _get_sqlmodel_field_value (field_info , "index" , Undefined )
719766 if index is Undefined :
720767 index = False
721768 nullable = not primary_key and is_field_noneable (field )
722769 # Override derived nullability if the nullable property is set explicitly
723770 # on the field
724- field_nullable = getattr (field_info , "nullable" , Undefined ) # noqa: B009
771+ field_nullable = _get_sqlmodel_field_value (field_info , "nullable" , Undefined )
725772 if field_nullable is not Undefined :
726773 assert not isinstance (field_nullable , UndefinedType )
727774 nullable = field_nullable
728775 args = []
729- foreign_key = getattr (field_info , "foreign_key" , Undefined )
776+ foreign_key = _get_sqlmodel_field_value (field_info , "foreign_key" , Undefined )
730777 if foreign_key is Undefined :
731778 foreign_key = None
732- unique = getattr (field_info , "unique" , Undefined )
779+ unique = _get_sqlmodel_field_value (field_info , "unique" , Undefined )
733780 if unique is Undefined :
734781 unique = False
735782 if foreign_key :
736- if field_info .ondelete == "SET NULL" and not nullable :
783+ ondelete_value = _get_sqlmodel_field_value (field_info , "ondelete" , Undefined )
784+ if ondelete_value is Undefined :
785+ ondelete_value = None
786+ if ondelete_value == "SET NULL" and not nullable :
737787 raise RuntimeError ('ondelete="SET NULL" requires nullable=True' )
738788 assert isinstance (foreign_key , str )
739- ondelete = getattr (field_info , "ondelete" , Undefined )
740- if ondelete is Undefined :
741- ondelete = None
742- assert isinstance (ondelete , (str , type (None ))) # for typing
743- args .append (ForeignKey (foreign_key , ondelete = ondelete ))
789+ assert isinstance (ondelete_value , (str , type (None ))) # for typing
790+ args .append (ForeignKey (foreign_key , ondelete = ondelete_value ))
744791 kwargs = {
745792 "primary_key" : primary_key ,
746793 "nullable" : nullable ,
@@ -754,10 +801,12 @@ def get_column_from_field(field: Any) -> Column: # type: ignore
754801 sa_default = field_info .default
755802 if sa_default is not Undefined :
756803 kwargs ["default" ] = sa_default
757- sa_column_args = getattr (field_info , "sa_column_args" , Undefined )
804+ sa_column_args = _get_sqlmodel_field_value (field_info , "sa_column_args" , Undefined )
758805 if sa_column_args is not Undefined :
759806 args .extend (list (cast (Sequence [Any ], sa_column_args )))
760- sa_column_kwargs = getattr (field_info , "sa_column_kwargs" , Undefined )
807+ sa_column_kwargs = _get_sqlmodel_field_value (
808+ field_info , "sa_column_kwargs" , Undefined
809+ )
761810 if sa_column_kwargs is not Undefined :
762811 kwargs .update (cast (Dict [Any , Any ], sa_column_kwargs ))
763812 return Column (sa_type , * args , ** kwargs ) # type: ignore
0 commit comments