2727 SmallIntegerField ,
2828)
2929from django .db .models .query_utils import DeferredAttribute
30+
31+ try :
32+ from django .db .models .expressions import DatabaseDefault
33+ except ImportError : # pragma: no cover
34+ class DatabaseDefault : # type: ignore
35+ """Spoof DatabaseDefault for Django < 5.0"""
36+
3037from django_enum .choices import choices , values
3138from django_enum .forms import EnumChoiceField , NonStrictSelect
3239
@@ -56,7 +63,11 @@ class ToPythonDeferredAttribute(DeferredAttribute):
5663
5764 def __set__ (self , instance : Model , value : Any ):
5865 try :
59- instance .__dict__ [self .field .name ] = self .field .to_python (value )
66+ instance .__dict__ [self .field .name ] = (
67+ value
68+ if isinstance (value , DatabaseDefault ) else
69+ self .field .to_python (value )
70+ )
6071 except (ValidationError , ValueError ):
6172 # Django core fields allow assignment of any value, we do the same
6273 instance .__dict__ [self .field .name ] = value
@@ -83,19 +94,10 @@ class EnumMixin(
8394 enum : Optional [Type [Enum ]] = None
8495 strict : bool = True
8596 coerce : bool = True
97+ primitive : Type [Any ]
8698
8799 descriptor_class = ToPythonDeferredAttribute
88100
89- def _coerce_to_value_type (self , value : Any ) -> Enum :
90- """Coerce the value to the enumerations value type"""
91- # note if enum type is int and a floating point is passed we could get
92- # situations like X.xxx == X - this is acceptable
93- if self .enum :
94- return type (values (self .enum )[0 ])(value )
95- # can't ever reach this - just here to make type checker happy
96- return value # pragma: no cover
97-
98-
99101 def __init__ (
100102 self ,
101103 * args ,
@@ -121,30 +123,42 @@ def _try_coerce(
121123 and non-strict, coercion to enum's primitive type will be done,
122124 otherwise a ValueError is raised.
123125 """
124- if (
125- (self .coerce or force )
126- and self .enum is not None
127- and not isinstance (value , self .enum )
128- ):
126+ if self .enum is None :
127+ return value
128+
129+ if (self .coerce or force ) and not isinstance (value , self .enum ):
129130 try :
130131 value = self .enum (value )
131132 except (TypeError , ValueError ):
132133 try :
133- value = self ._coerce_to_value_type (value )
134+ value = self .primitive (value )
134135 value = self .enum (value )
135136 except (TypeError , ValueError ):
136137 try :
137138 value = self .enum [value ]
138139 except KeyError as err :
139140 if self .strict or not isinstance (
140141 value ,
141- type ( values ( self .enum )[ 0 ])
142+ self .primitive
142143 ):
143144 raise ValueError (
144145 f"'{ value } ' is not a valid "
145146 f"{ self .enum .__name__ } "
146147 f"required by field { self .name } ."
147148 ) from err
149+ elif (
150+ not self .coerce and
151+ not isinstance (value , self .primitive ) and
152+ not isinstance (value , self .enum )
153+ ):
154+ try :
155+ return self .primitive (value )
156+ except (TypeError , ValueError ) as err :
157+ raise ValueError (
158+ f"'{ value } ' is not coercible to { self .primitive .__name__ } "
159+ f"required by field { self .name } ."
160+ ) from err
161+
148162 return value
149163
150164 def deconstruct (self ) -> Tuple [str , str , List , dict ]:
@@ -306,6 +320,8 @@ class EnumCharField(EnumMixin, CharField):
306320 A database field supporting enumerations with character values.
307321 """
308322
323+ primitive = str
324+
309325 def __init__ (self , * args , enum = None , ** kwargs ):
310326 kwargs .setdefault (
311327 'max_length' ,
@@ -320,48 +336,61 @@ def __init__(self, *args, enum=None, **kwargs):
320336class EnumFloatField (EnumMixin , FloatField ):
321337 """A database field supporting enumerations with floating point values"""
322338
339+ primitive = float
340+
323341
324342class EnumSmallIntegerField (EnumMixin , SmallIntegerField ):
325343 """
326344 A database field supporting enumerations with integer values that fit into
327345 2 bytes or fewer
328346 """
329347
348+ primitive = int
349+
330350
331351class EnumPositiveSmallIntegerField (EnumMixin , PositiveSmallIntegerField ):
332352 """
333353 A database field supporting enumerations with positive (but signed) integer
334354 values that fit into 2 bytes or fewer
335355 """
336356
357+ primitive = int
337358
338359class EnumIntegerField (EnumMixin , IntegerField ):
339360 """
340361 A database field supporting enumerations with integer values that fit into
341362 32 bytes or fewer
342363 """
343364
365+ primitive = int
366+
344367
345368class EnumPositiveIntegerField (EnumMixin , PositiveIntegerField ):
346369 """
347370 A database field supporting enumerations with positive (but signed) integer
348371 values that fit into 32 bytes or fewer
349372 """
350373
374+ primitive = int
375+
351376
352377class EnumBigIntegerField (EnumMixin , BigIntegerField ):
353378 """
354379 A database field supporting enumerations with integer values that fit into
355380 64 bytes or fewer
356381 """
357382
383+ primitive = int
384+
358385
359386class EnumPositiveBigIntegerField (EnumMixin , PositiveBigIntegerField ):
360387 """
361388 A database field supporting enumerations with positive (but signed) integer
362389 values that fit into 64 bytes or fewer
363390 """
364391
392+ primitive = int
393+
365394
366395class _EnumFieldMetaClass (type ):
367396
0 commit comments