tortoise / tortoise/tortoise-orm

Missing attributes when using fetch_related

Open
#932 0 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
Hello,

I am using FastApi+Tortoise to simulate a small Facebook-like demo project. I have users linked to friend requests, where each friend request has a requestor and a requestee.

The user object derived from awaiting Users.filter(...).first(...) correctly shows related obejcts in the friendships_requestee and friendships_requestor attributes:

image

The derived pydantic model however drops the references to the user objects in the friend requests:

image

I appreciate that keeping a reference to the current user might be redundant, but it would be helpful to keep a reference to the other user

To Reproduce
Models:

class Users(models.Model):
    """
    The User model
    """

    id = fields.CharField(pk=True, max_length=100)
    #: This is a username
    username = fields.CharField(max_length=20, unique=True)
    name = fields.CharField(max_length=50, null=True)
    email = fields.CharField(max_length=320, null=False)
    friends: fields.ManyToManyRelation["Users"] = fields.ManyToManyField(
        'models.Users', through='friendships', null=False, default=[]
    )

class FriendRequest(models.Model):
    requestor = fields.ForeignKeyField('models.Users', null=False, related_name='friendships_requestor')
    requestee = fields.ForeignKeyField('models.Users', null=False, related_name='friendships_requestee')
    created_at = fields.DatetimeField(auto_now=True)
    accepted_at = fields.DatetimeField(null=True)

    class Meta:
        unique_together=(('requestor', 'requestee'))

Fetching:

user = await Users.filter(id=user_id).first()
    await user.fetch_related("friendships_requestee__requestor")
    await user.fetch_related("friendships_requestee__requestee")
    await user.fetch_related("friendships_requestor__requestor")
    await user.fetch_related("friendships_requestor__requestor")

    user_pydantic = await UserOut_Pydantic.from_tortoise_orm(user)

Expected behavior

User FKs in FriendRequest objects retrieved with fetch_related to be kept.

Additional context
I was able to 'hack' a solution by manually creating and populating the models:

class FriendRequestOut(BaseModel):
    requestor_id: str
    requestee_id: str
    created_at: datetime
    accepted_at: Union[datetime, None]


class TestUserOut(BaseModel):
    id: str
    username: str
    email: str
    friendships_requestor: List[FriendRequestOut]
    friendships_requestee: List[FriendRequestOut]

 test_user_out = TestUserOut(**{
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'friendships_requestor': [FriendRequestOut(**{
            'created_at': related_object.created_at,
            'accepted_at': related_object.accepted_at,
            'requestor_id': related_object.requestor_id,
            'requestee_id': related_object.requestee_id
        }) for related_object in user.friendships_requestor.related_objects],
        'friendships_requestee': [FriendRequestOut(**{
            'created_at': related_object.created_at,
            'accepted_at': related_object.accepted_at,
            'requestor_id': related_object.requestor_id,
            'requestee_id': related_object.requestee_id
        }) for related_object in user.friendships_requestee.related_objects]
    })

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 with the fetch_related calls and UserOut_Pydantic.from_tortoise_orm shown in the reproduction, then trace how the loaded FriendRequest relations are converted into Pydantic models. Reproduce the example and verify that the expected user foreign-key references are retained in the serialized FriendRequest objects.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, python
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.