tortoise / tortoise-orm

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

Prefetch_related raises FieldError in 0.16.8 with asyncpg #369

Closed bbedward closed 4 years ago

bbedward commented 4 years ago

Describe the bug The following query produces an exception:

await Account.filter(address=link).prefetch_related('user').first()

Account Model:

class Account(Model):
    user = fields.OneToOneField('db.User', related_name='account', index=True)
    address = fields.CharField(max_length=65, unique=True, index=True)

    class Meta:
        table = 'accounts'
class User(Model):
    id = fields.BigIntField(pk=True, generated=False)
    name = fields.CharField(max_length=50)
    created_at = fields.DatetimeField(auto_now_add=True)
    modified_at = fields.DatetimeField(auto_now=True)
    frozen = fields.BooleanField(default=False) # Completely banned
    tip_banned = fields.BooleanField(default=False) # Can't receive tips

    class Meta:
        table = "users"

The exception is as follows:

ERROR:aiohttp.server:Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 418, in start
    resp = await task
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_app.py", line 458, in _handle
    resp = await handler(request)
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_middlewares.py", line 119, in impl
    return await handler(request)
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_middlewares.py", line 109, in impl
    return await handler(request)
  File "/usr/src/app/server.py", line 155, in callback
    account = await Account.filter(address=link).prefetch_related('user').first()
  File "/usr/local/lib/python3.7/site-packages/tortoise/queryset.py", line 699, in _execute
    ).execute_select(self.query, custom_fields=list(self._annotations.keys()))
  File "/usr/local/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 115, in execute_select
    await self._execute_prefetch_queries(instance_list)
  File "/usr/local/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 440, in _execute_prefetch_queries
    await asyncio.gather(*prefetch_tasks)
  File "/usr/local/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 431, in _do_prefetch
    return await self._prefetch_direct_relation(instance_id_list, field, related_query)
  File "/usr/local/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 398, in _prefetch_direct_relation
    **{f"{k}__in": v for k, v in related_objects_for_fetch.items()}
  File "/usr/local/lib/python3.7/site-packages/tortoise/queryset.py", line 686, in __await__
    self._make_query()
  File "/usr/local/lib/python3.7/site-packages/tortoise/queryset.py", line 674, in _make_query
    custom_filters=self._custom_filters,
  File "/usr/local/lib/python3.7/site-packages/tortoise/queryset.py", line 110, in resolve_filters
    modifier &= node.resolve(model, annotations, custom_filters, model._meta.basetable)
  File "/usr/local/lib/python3.7/site-packages/tortoise/query_utils.py", line 379, in resolve
    return self._resolve_kwargs(model, table)
  File "/usr/local/lib/python3.7/site-packages/tortoise/query_utils.py", line 333, in _resolve_kwargs
    key, value = self._get_actual_filter_params(model, raw_key, raw_value)
  File "/usr/local/lib/python3.7/site-packages/tortoise/query_utils.py", line 327, in _get_actual_filter_params
    raise FieldError(f"Unknown filter param '{key}'. Allowed base values are {allowed}")
tortoise.exceptions.FieldError: Unknown filter param 'None__in'. Allowed base values are ['account', 'created_at', 'favorited_by', 'favorites', 'frozen', 'id', 'modified_at', 'muted', 'muted_by', 'name', 'received_transactions', 'sent_transactions', 'started_giveaways', 'stats', 'tip_banned', 'won_giveaways']

To Reproduce Run a .prefetch_related query with .first() on a postgres database

await Account.filter(address=link).prefetch_related('user').first()

Expected behavior Query returns a single Account object or None, if account doesn't exist.

Additional context This recently popped up after upgrading to tortoise-orm 0.16.8 from 0.15.5, it's a regression with the newer versions.

grigi commented 4 years ago

Oh, I think I fixed that issue in the 0.16.9 release. It was specific to a prefetch on a one-to-one field.

Could you please test 0.16.9 and see if it fixes your issue?

bbedward commented 4 years ago

Tested v0.16.9 and it appears to be fixed.

Thanks again for the fast response!