tortoise-orm
tortoise-orm copied to clipboard
Unexpected call to `to_python_value` when creating new "Model"
Describe the bug Models needs to take in db value when creating model instead of pythonic value.
To Reproduce
import traceback
from typing import List
from tortoise import Model, Tortoise, run_async
from tortoise.fields import TextField
class TextListField(TextField):
__SEPERATOR = ", "
def __init__(self, **kwargs):
super().__init__(**kwargs)
def to_db_value(self, value: List[str], instance) -> str:
print(f"`to_db_value` provided value type is {type(value)}")
return self.__SEPERATOR.join(value)
def to_python_value(self, value: str) -> List[str]:
print(f"`to_python_value` provided value type is {type(value)}")
return value.split(self.__SEPERATOR)
class Test(Model):
list = TextListField()
async def init():
await Tortoise.init(
db_url='sqlite://db.sqlite3',
modules={'models': ['__main__']}
)
await Tortoise.generate_schemas()
try:
await Test.create(list=["a", "b"])
except AttributeError:
data = traceback.format_exc()
print(data)
await Test.create(list="a, b")
if __name__ == '__main__':
run_async(init())
Output for first create:
`to_python_value` provided value type is <class 'list'>
Traceback (most recent call last):
File "E:\Codes\main.py", line 36, in make_test_with_list
await Test.create(list=["a", "b"])
File "E:\Codes\venv\lib\site-packages\tortoise\models.py", line 1132, in create
instance = cls(**kwargs)
File "E:\Codes\venv\lib\site-packages\tortoise\models.py", line 671, in __init__
for key in meta.fields.difference(self._set_kwargs(kwargs)):
File "E:\Codes\venv\lib\site-packages\tortoise\models.py", line 698, in _set_kwargs
setattr(self, key, field_object.to_python_value(value))
File "E:\Codes\main.py", line 20, in to_python_value
return value.split(self.__SEPERATOR)
AttributeError: 'list' object has no attribute 'split'
Output for second create:
`to_python_value` provided value type is <class 'str'>
`to_db_value` provided value type is <class 'list'>
Process finished with exit code 0
Expected behavior My expectation is that in the first create shouldn't fail
Additional context
In my opinion the call to to_python_value
isn't supposed to happen.
Hi, @AntsyLich
Use of Model.create(**data)
or Model(**data)
will cause Tortoise to call the Field.to_python_value
ensuring each field model receives its value having the expected types.
Case you want to allow different value types (str
, list
, and whatever), you can make your to_python_value
a little more dynamic using singledispatchmethod.