tortoise / tortoise/tortoise-orm
Complex prefetch does not respect .only and always creates a full model
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
I am looking for a way to only fetch the primary keys of a many to many relation.
It's possible to to pass a queryset to Prefetch which should only create a partial model.
However currently this is ignored and always a full model is created which is a bug.
To Reproduce
from tortoise import fields, run_async, Tortoise
from tortoise.fields import ManyToManyRelation, ManyToManyField
from tortoise.models import Model
from tortoise.query_utils import Prefetch
class MyModel(Model):
id = fields.IntField(pk=True)
name = fields.TextField()
properties: ManyToManyRelation["Property"]
class Property(Model):
id = fields.IntField(pk=True)
name = fields.TextField()
my_models: ManyToManyRelation["MyModel"] = ManyToManyField("models.MyModel", related_name='properties')
async def run():
# Generate the schema
await Tortoise.init({"connections": {"default_connection": {"engine": "tortoise.backends.sqlite", "credentials": {"file_path": ':memory:'},},}, "apps": {"models": {"models": ['__main__'], "default_connection": "default_connection"},},})
await Tortoise.generate_schemas()
m1 = await MyModel.create(id=1, name='Model1')
p1 = await Property.create(id=1, name='Property 1')
await m1.properties.add(p1)
# Fetch only ids with Prefetch
objs = await MyModel.filter(pk=1).prefetch_related(
Prefetch('properties', queryset=Property.all().only('id')),
)
print(objs)
for e in objs[0].properties:
print(e)
print(e.name) # <-- this does not crash but it should since this should only be a partial model
run_async(run())
Additional context
It would be nice if fetching the pks would be possible with the normal prefetch.
e.g.:
await MyModel.get(pk=1).first().prefetch_related('properties__id'')
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproduction and trace Prefetch in tortoise.query_utils together with ManyToManyRelation and ManyToManyField handling. Run the SQLite example with Property.all().only('id'); done means the prefetched relation preserves the partial model instead of creating a full model, so accessing the unloaded name field behaves as expected.
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