tortoise / tortoise-orm

Familiar asyncio ORM for python, built with relations in mind
https://tortoise.github.io
Apache License 2.0
4.64k stars 386 forks source link

Crazy id counters #731

Closed Olegt0rr closed 3 years ago

Olegt0rr commented 3 years ago

Describe the bug

Id counters depends on another models and not increases for model without additional fields.

To Reproduce


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

class Foo(Model):
    id = IntField(pk=True)

class Bar(Model):
    id = IntField(pk=True)
    name = CharField(max_length=32, null=True)

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

    foo_1 = await Foo.create()
    print(foo_1, foo_1.id)

    foo_2 = await Foo.create()
    print(foo_2, foo_2.id)

    bar_1 = await Bar.create()
    print(bar_1, bar_1.id)

    bar_2 = await Bar.create()
    print(bar_2, bar_2.id)

    foo_3 = await Foo.create()
    print(foo_3, foo_3.id)

    foo_4 = await Foo.create()
    print(foo_4, foo_4.id)

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

Result

<Foo> 0
<Foo> 0
<Bar> 1
<Bar> 2
<Foo> 2
<Foo> 2

Expected result

<Foo> 1
<Foo> 2
<Bar> 1
<Bar> 2
<Foo> 3
<Foo> 4

Workaround

Add another one field to Foo model

class Foo(Model):
    id = IntField(pk=True)
    name = CharField(max_length=32, null=True)

This way id counts properly!

isaquealves commented 3 years ago

I'm not sure this is a bug. This only happens if your model doesn't have any attributes but id. Let's think: Should we expect to have a real model with only an id and no other attributes?

Olegt0rr commented 3 years ago

I'm not sure this is a bug. This only happens if your model doesn't have any attributes but id. Let's think: Should we expect to have a real model with only an id and no other attributes?

I know, it's a weird case, but why not? This behaviour is weird too (using neighboor model ID is not a good solution)

long2ice commented 3 years ago

That's senseless

marcoaaguiar commented 3 years ago

I found why this is happening. I was developing some tests for a tortoise-related bug fix for fastapi-crudrouter where I didn't need any field in the Model other than the PK so that I could make an FK relation. I found that the insert query is empty!

If there is no other field other than the primary key, this is what happens:

https://github.com/tortoise/tortoise-orm/blob/e83604c33a0cef1f34fa6ed7121d1d770a52f9c5/tortoise/backends/base/executor.py#L68-L69

  1. column is empty ([])
  2. since column is empty self.insert_query is empty ("" instead of a "INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, value, ...);" or something similar)
  3. When executing an insert query, it will return 0 (and not save it on the DB).
  4. For some reason that I haven't tested, it returns the last id if the insert is executed after a previous succeeding insert.

This should be considered a bug, from the Zen of Python:

Errors should never pass silently.

If creating a Model with only an id field is an error, Tortoise should raise an error. Which doesn't make sense since this is a completely valid model/table in all supported DBs.

long2ice commented 3 years ago

raise a exception is a choice