Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

model.update_or_create KeyError #1583

Open
jiangying000 opened this issue Apr 10, 2024 · 3 comments
Open

model.update_or_create KeyError #1583

jiangying000 opened this issue Apr 10, 2024 · 3 comments

Comments

@jiangying000
Copy link

jiangying000 commented Apr 10, 2024

return await cls.create(using_db=connection, **defaults, **kwargs), True

would cause KeyError for following code:

class Faqs(BaseModel):
    id = fields.UUIDField(pk=True)
    question = fields.TextField(null=True)

@pytest.mark.asyncio
async def test_tortoise_update_or_create():
    # suppose entry exists
    faq = await Faqs.get(id="6aadafff-e0b9-497b-aeb2-65498a35b6f5")
    # modify question
    faq.question = "q111234"
    # assign new id
    faq.id = uuid.uuid4()
    # update_or_create, KeyError
    new_faq = await Faqs.update_or_create(id=faq.id, defaults=dict(faq))


ERROR like:

    @classmethod
    async def get_or_create(
        cls: Type[MODEL],
        defaults: Optional[dict] = None,
        using_db: Optional[BaseDBAsyncClient] = None,
        **kwargs: Any,
    ) -> Tuple[MODEL, bool]:
        """
        Fetches the object if exists (filtering on the provided parameters),
        else creates an instance with any unspecified parameters as default values.
    
        :param defaults: Default values to be added to a created instance if it can't be fetched.
        :param using_db: Specific DB connection to use instead of default bound
        :param kwargs: Query parameters.
        :raises IntegrityError: If create failed
        :raises TransactionManagementError: If transaction error
        """
        if not defaults:
            defaults = {}
        db = using_db or cls._choose_db(True)
        async with in_transaction(connection_name=db.connection_name) as connection:
            try:
                return (
                    await cls.select_for_update()
                    .filter(**kwargs)
                    .using_db(connection)
                    .get(),
                    False,
                )
            except DoesNotExist:
                try:
                    return (
>                       await cls.create(using_db=connection, **defaults, **kwargs),
                        True,
                    )
E                   KeyError: 'id'

..\.venv\lib\site-packages\tortoise\models.py:1102: KeyError



@waketzheng
Copy link
Contributor

I got different errors with the following code snippet:

import uuid

from tortoise import Tortoise, fields, run_async
from tortoise.models import Model


class Faqs(Model):
    id = fields.UUIDField(pk=True)
    question = fields.TextField(null=True)


async def run():
    await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})
    await Tortoise.generate_schemas()

    faq, _ = await Faqs.get_or_create(id="6aadafff-e0b9-497b-aeb2-65498a35b6f5")
    # modify question
    faq.question = "q111234"
    # assign new id
    faq.id = uuid.uuid4()
    # update_or_create, KeyError
    new_faq, created = await Faqs.update_or_create(id=faq.id, defaults=dict(faq))
    print(dict(new_faq), created)


if __name__ == "__main__":
    run_async(run())

ERROR is:

Traceback (most recent call last):
  File "/home/wenping/github/tortoise-orm/tortoise/models.py", line 1079, in get_or_create
    await cls.select_for_update().filter(**kwargs).using_db(connection).get(),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/wenping/github/tortoise-orm/tortoise/queryset.py", line 1074, in _execute
    raise DoesNotExist("Object does not exist")
tortoise.exceptions.DoesNotExist: Object does not exist

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/wenping/github/tortoise-orm/examples/fastapi/run.py", line 27, in <module>
    run_async(run())
  File "/home/wenping/github/tortoise-orm/tortoise/__init__.py", line 688, in run_async
    loop.run_until_complete(coro)
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 685, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/wenping/github/tortoise-orm/examples/fastapi/run.py", line 22, in run
    new_faq, created = await Faqs.update_or_create(id=faq.id, defaults=dict(faq))
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/wenping/github/tortoise-orm/tortoise/models.py", line 1129, in update_or_create
    return await cls.get_or_create(defaults, db, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/wenping/github/tortoise-orm/tortoise/models.py", line 1084, in get_or_create
    return await cls.create(using_db=connection, **defaults, **kwargs), True
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: tortoise.models.Model.create() got multiple values for keyword argument 'id'

@waketzheng
Copy link
Contributor

After change the Python version to 3.10, got the KeyError:

Traceback (most recent call last):
  File "/home/wenping/github/tortoise-orm/tortoise/models.py", line 1079, in get_or_create
    await cls.select_for_update().filter(**kwargs).using_db(connection).get(),
  File "/home/wenping/github/tortoise-orm/tortoise/queryset.py", line 1074, in _execute
    raise DoesNotExist("Object does not exist")
tortoise.exceptions.DoesNotExist: Object does not exist

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/wenping/github/tortoise-orm/examples/fastapi/run.py", line 27, in <module>
    run_async(run())
  File "/home/wenping/github/tortoise-orm/tortoise/__init__.py", line 688, in run_async
    loop.run_until_complete(coro)
  File "/home/wenping/.pyenv/versions/3.10.2/lib/python3.10/asyncio/base_events.py", line 641, in run_until_complete
    return future.result()
  File "/home/wenping/github/tortoise-orm/examples/fastapi/run.py", line 22, in run
    new_faq, created = await Faqs.update_or_create(id=faq.id, defaults=dict(faq))
  File "/home/wenping/github/tortoise-orm/tortoise/models.py", line 1129, in update_or_create
    return await cls.get_or_create(defaults, db, **kwargs)
  File "/home/wenping/github/tortoise-orm/tortoise/models.py", line 1084, in get_or_create
    return await cls.create(using_db=connection, **defaults, **kwargs), True
KeyError: 'id'

@waketzheng
Copy link
Contributor

For why it raises KeyError instead of TypeError with Python<3.12, see this: https://stackoverflow.com/questions/78427983/why-does-dictid-1-id-2-sometimes-raise-keyerror-id-instead-of-a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants