For example I have this code:
class SomeModel(models.Model):
instance_name = models.UnknownField(max_length=255)
instance_id = models.IntegerField()
I want to have the model name (SomeModel
) and field name (for ex. instance_name
) as an input, and the, and the output will be the python representation of that field (for ex.: srt, int, float...)
So it will be something like this:
def find_out_the_field_python_type(model: Model, field_name: str) -> type:
# For example model = SomeModel, field_name = instance_id
# return int
return
I have tried this:
instance_id_field = SomeModel._meta.get_field('instance_id')
# Determine the Python representation of the field
python_representation = instance_id_field.get_internal_type()
print(python_representation)
# returns 'IntegerField'
But the problem that it returns not the python representation, but the type of Django field.
I don't think what you want is really do-able. The Source code is available. It appears that the Python type is not a meta variable, but is hard-coded into the to_python
method of the field.
The model is an interface between Python and a database. Not all databases directly support all Django field types. Where they don't, Django performs an encoding to store and a decoding to initialize a model instance.
This, for example, is the to_python
method for a DecimalField from the above source:
def to_python(self, value):
if value is None:
return value
if isinstance(value, float):
return self.context.create_decimal_from_float(value)
try:
return decimal.Decimal(value)
except (decimal.InvalidOperation, TypeError, ValueError):
raise exceptions.ValidationError(
self.error_messages['invalid'],
code='invalid',
params={'value': value},
)
If you were determined you could run an iteration feeding plausible values into the to_python
method until you get a successful return. Before doing this you'd want to check the field's concrete
(True) and is_relation
(False) for appropriate other handling.
instance_id_field = SomeModel._meta.get_field('instance_id')
if instance_id_field.is_relation:
# ??
if not instance.id_field.is_concrete:
# ??
for thing in (
'0', # should work for Charfield and numeric fields and Boolean
datetime.datetime( 2023,1,1), # for all date or datetime,
0.0, # for above DecimalField,
... # work through the above-linked source for other probe values!
):
try:
x = instance_id_field.to_python( thing)
return type(x)
except Exception:
pass
raise TypeError(
f'Unable to determine Python type of {instance_id_field}')
But this is really horribly hacky.