tortoise / tortoise/tortoise-orm

Unexpected call to `to_python_value` when creating new "Model"

Open
#1,219 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Python
Stars
5.6k
Forks
516
Avg merge
2d 21h
Merged PRs (30d)
9

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in tortoise/models.py at Model.init and _set_kwargs, where the traceback shows to_python_value being called during model creation. Reproduce the two Test.create cases from the issue and trace the field-value flow. Done means the first create no longer fails while the existing database conversion behavior remains correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.