tortoise / tortoise-orm

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

relation not found - How to use .fetch_related()? #1514

Open pyahmed opened 10 months ago

pyahmed commented 10 months ago

Describe the bug I've setup a ForeignKey field and appropriate model. When fetching the object I can't access the object under the ForeignKey field. Using .fetch_related says relation not found.

To Reproduce

# mymodels.py

from tortoise.models import Model
from tortoise import fields

class Preset(Model):
    name = fields.CharField(max_length=255)
    setting1 = fields.ForeignKeyField('models.Setting1', related_name='preset')

    def __str__(self):
        return self.name

class Setting1(Model):
    name = fields.CharField(max_length=255)

    def __str__(self):
        return self.name
# setup_data_and_test.py

from mymodels import *
from tortoise import Tortoise, run_async

async def init():
    await Tortoise.init(db_url='sqlite://db.sqlite3',  modules={'models': ['mymodels']})
    await Tortoise.generate_schemas()

async def add_data():
    s1 = await Setting1.create(name="Test-Setting1")
    p1 = await Preset.create(name="Preset1", setting1=s1)

async def done():
    await Tortoise.close_connections()

async def get_data():
    all_presets = await Preset.all()
    for entry in all_presets:
        print('Preset:', entry.name)

    await all_presets[0].fetch_related('preset')
    print(all_presets[0].setting1.name)

run_async(init())
run_async(add_data())
run_async(get_data())
run_async(done())

So when I run setup_data_and_test.py I get:

$ setup_data_and_test.py
Preset: Preset1
Traceback (most recent call last):
  File "D:\tortoise_orm_example\setup_data_and_test.py", line 25, in <module>
    run_async(get_data())
  File "C:\Python310\lib\site-packages\tortoise\__init__.py", line 688, in run_async
    loop.run_until_complete(coro)
  File "C:\Python310\lib\asyncio\base_events.py", line 646, in run_until_complete
    return future.result()
  File "D:\tortoise_orm_example\setup_data_and_test.py", line 20, in get_data
    await all_presets[0].fetch_related('preset')
  File "C:\Python310\lib\site-packages\tortoise\models.py", line 994, in fetch_related
    await db.executor_class(model=self.__class__, db=db).fetch_for_list([self], *args)
  File "C:\Python310\lib\site-packages\tortoise\backends\base\executor.py", line 585, in fetch_for_list
    raise OperationalError(
tortoise.exceptions.OperationalError: relation preset for preset not found

Expected behavior I would expect to access the data of the FK-object. Or am I missing something here? How could I access objects under ForeignKey-fields?

Additional context tortoise-orm: 0.20.0 OS: Win 10/x64 Py: Python 3.10.6

Prof1-web commented 10 months ago

You Preset model doesn't have preset field. So you can't load this relation

pyahmed commented 10 months ago

I was following the Getting started examples from here: https://tortoise.github.io/getting_started.html

Where .prefetch_related() is used in the same way, not sure why but I thought .fetch_related() would work the same way. Apprently not, but it does work with .fetch_related('setting1').

Prof1-web commented 10 months ago

Getting started:

class Event(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)
    # References to other models are defined in format
    # "{app_name}.{model_name}" - where {app_name} is defined in tortoise config
    tournament = fields.ForeignKeyField('models.Tournament', related_name='events')
    participants = fields.ManyToManyField('models.Team', related_name='events', through='event_team')

    def __str__(self):
        return self.name

selected_events = await Event.filter(
    participants=participants[0].id
).prefetch_related('participants', 'tournament')

The Event has participants and tournament fields. So It works. You model doesn't have the field you're trying to use, so it doesn't work.