tortoise / tortoise/tortoise-orm

Misbehaving model `save()` when names are too long

Open
#2,018 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Describe the bug
Model save() is not working when the model name and field name is too long and select_related is used.

To Reproduce

Tortoise ORM version: 0.25.1

Creating the test models:

from tortoise.models import Model
from tortoise import fields

class TUser(Model):
    id = fields.UUIDField(primary_key=True)
    name = fields.CharField(max_length=100)

    user_information: fields.ReverseRelation["models.VeryLongNameForTestingPurposesOnlyUserInfo"]
    short_user_info: fields.ReverseRelation["models.ShortUserInfo"]


class VeryLongNameForTestingPurposesOnlyUserInfo(Model):
    id = fields.UUIDField(primary_key=True)
    user: fields.OneToOneNullableRelation[TUser] = fields.OneToOneField(
        model_name="models.TUser",
        to_field="id",
        related_name="user_information"
    )
    not_too_long_user_age = fields.IntField()


class ShortUserInfo(Model):
    id = fields.UUIDField(primary_key=True)
    user: fields.OneToOneNullableRelation[TUser] = fields.OneToOneField(
        model_name="models.TUser",
        to_field="id",
        related_name="short_user_info"
    )
    age = fields.IntField()

Reproducing the issue:

    print("Creating user and user info")
    user = await TUser.create(name="Test User")
    user_info = await VeryLongNameForTestingPurposesOnlyUserInfo.create(
        user_id=user.id,
        not_too_long_user_age=30,
    )
    short_info = await ShortUserInfo.create(
        user_id=user.id,
        age=30,
    )

    print("Working")
    user = await TUser.filter(name="Test User").select_related("short_user_info").first()
    user_info = user.short_user_info
    user_info.age = 31
    await user_info.save()
    
    print("Not Working")
    user = await TUser.filter(name="Test User").select_related("user_information").first()
    user_info = user.user_information
    user_info.not_too_long_user_age = 32
    await user_info.save(
        # update_fields=["not_too_long_user_age"]
    )

This will raise:

IncompleteInstanceError: VeryLongNameForTestingPurposesOnlyUserInfo is a partial model, can only be saved with the relevant update_field provided

(Saving with update_fields works.)

Expected behavior
Saving with select_related should work regardless of the model name length.

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

Run the supplied reproduction with the long and short related model names, then compare the select_related paths that lead to each save(). Trace how partial models and selected fields are tracked before IncompleteInstanceError is raised. Done means saving the related object succeeds without update_fields regardless of model name length, while the existing update_fields behavior remains valid.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
database
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.