33
44from functools import partial
55
6+ from django .core .exceptions import FieldError
67from django .db .models .fields import NOT_PROVIDED
78from django .db .models .query_utils import DeferredAttribute
89from django .db .models import JSONField
1213
1314from . import base
1415
15- __all__ = "SchemaField" ,
16+ __all__ = ( "SchemaField" ,)
1617
1718
1819class SchemaDeferredAttribute (DeferredAttribute ):
@@ -38,30 +39,35 @@ class PydanticSchemaField(base.SchemaWrapper["base.ST"], JSONField):
3839
3940 def __init__ (
4041 self ,
41- schema : t .Union [t .Type ["base.ST" ], "GenericContainer" ],
42- config : "base.ConfigType" = None ,
4342 * args ,
43+ schema : t .Union [t .Type ["base.ST" ], "GenericContainer" ] = None ,
44+ config : "base.ConfigType" = None ,
4445 error_handler = base .default_error_handler ,
4546 ** kwargs
4647 ):
47- if isinstance (schema , GenericContainer ):
48- schema = t .cast (t .Type ["base.ST" ], schema .reconstruct_type ())
48+ super ().__init__ (* args , ** kwargs )
4949
50- self .schema = schema
5150 self .config = config
52- self .export_cfg = self ._extract_export_kwargs (kwargs , dict .pop )
53-
54- field_schema = self ._wrap_schema (schema , config )
55- decoder = partial (base .SchemaDecoder , schema = field_schema , error_handler = error_handler )
56- encoder = partial (base .SchemaEncoder , schema = field_schema , export_cfg = self .export_cfg )
57-
58- kwargs .update (decoder = decoder , encoder = encoder )
59- super ().__init__ (* args , ** kwargs )
51+ self .export_params = self ._extract_export_kwargs (kwargs , dict .pop )
52+ self .error_handler = error_handler
53+ self ._init_schema (schema )
6054
6155 def __copy__ (self ):
6256 _ , _ , args , kwargs = self .deconstruct ()
6357 return type (self )(* args , ** kwargs )
6458
59+ def contribute_to_class (self , cls , name , private_only = False ):
60+ if self .schema is None :
61+ annotated_schema = t .get_type_hints (cls ).get (name , None )
62+ if annotated_schema is None :
63+ raise FieldError (
64+ f"{ cls ._meta .label } .{ name } needs to be either annotated "
65+ "or `schema=` field attribute should be explicitly passed"
66+ )
67+ self ._init_schema (annotated_schema )
68+
69+ super ().contribute_to_class (cls , name , private_only )
70+
6571 def get_default (self ):
6672 value = super ().get_default ()
6773 return self .to_python (value )
@@ -81,6 +87,19 @@ def to_python(self, value) -> "base.SchemaT":
8187 assert self .decoder is not None
8288 return self .decoder ().decode (value )
8389
90+ def _init_schema (
91+ self ,
92+ schema : t .Union [t .Type ["base.ST" ], "GenericContainer" , None ],
93+ ):
94+ if isinstance (schema , GenericContainer ):
95+ schema = t .cast (t .Type ["base.ST" ], schema .reconstruct_type ())
96+
97+ self .schema = schema
98+ if schema is not None :
99+ serializer = self ._wrap_schema (schema , self .config )
100+ self .decoder = partial (base .SchemaDecoder , serializer , self .error_handler ) # type: ignore
101+ self .encoder = partial (base .SchemaEncoder , schema = serializer , export = self .export_params ) # type: ignore
102+
84103 def _deconstruct_default (self , kwargs ):
85104 default = kwargs .get ("default" , NOT_PROVIDED )
86105
@@ -99,17 +118,20 @@ def _deconstruct_schema(self, kwargs):
99118 kwargs .update (schema = schema )
100119
101120 def _deconstruct_config (self , kwargs ):
102- kwargs .update (self .export_cfg , config = self .config )
121+ kwargs .update (self .export_params , config = self .config )
122+
123+ if self .error_handler is not base .default_error_handler :
124+ kwargs .update (error_handler = self .error_handler )
103125
104126
105127def SchemaField (
106- schema : t .Union [t .Type ["base.ST" ], "GenericContainer" ],
107- config : "base.ConfigType" = None ,
108128 * args ,
129+ schema : t .Type ["base.ST" ] = None ,
130+ config : "base.ConfigType" = None ,
109131 error_handler = base .default_error_handler ,
110132 ** kwargs
111133) -> t .Any :
112- return PydanticSchemaField (schema , config , * args , error_handler = error_handler , ** kwargs )
134+ return PydanticSchemaField (* args , schema = schema , config = config , error_handler = error_handler , ** kwargs )
113135
114136
115137# Django Migration serializer helpers
0 commit comments