tortoise / tortoise-orm

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

Multiple annotations don't work #683

Closed ArtemBernatskyy closed 1 day ago

ArtemBernatskyy commented 3 years ago
old_lotteries_pool = (
    await Lottery.filter(Q(status=LotteryStatus.ENDED) & Q(has_winners=False))
    .prefetch_related("tickets")
    .annotate(total_tickets=Count("tickets"))
    .annotate(lottery_pool=F("total_tickets") * F("ticket_price"))
)

I receive tortoise.exceptions.OperationalError: column "total_tickets" does not exist (in Django we could use multiple annotations)

PS I know it could be RTFM but I've tried searching issues / reading docs but without success, thx in advance for any help! PPS here is models that I use

from tortoise import fields
from tortoise.models import Model

from app.constants import LotteryStatus
from app.validators import PositiveValueValidator

class User(Model):
    """User table"""

    id = fields.BigIntField(pk=True)  # same as https://discordpy.readthedocs.io/en/latest/api.html#discord.User.id
    balance = fields.data.DecimalField(
        max_digits=15, decimal_places=2, default=0, validators=[PositiveValueValidator()]
    )
    created_at = fields.DatetimeField(auto_now_add=True)
    modified_at = fields.DatetimeField(auto_now=True)

    lotteries: fields.ReverseRelation["Lottery"]
    tickets: fields.ReverseRelation["Ticket"]

    def __str__(self):
        return f"#{self.id}"

class Lottery(Model):
    """Lottery table"""

    id = fields.UUIDField(pk=True)
    name = fields.CharField(max_length=255, unique=True)
    ticket_price = fields.data.DecimalField(max_digits=15, decimal_places=2, default=10)
    strike_date_eta = fields.data.DatetimeField()
    strike_eth_block = fields.IntField()
    winning_tickets = fields.JSONField(null=True)
    # there is a possibility when lottery doesn't have winners, in this case we will add lottery pool to the total pool
    # then if someone wins another lottery he will get total pool
    has_winners = fields.BooleanField(default=False)
    status = fields.CharEnumField(
        enum_type=LotteryStatus,
        default=LotteryStatus.STARTED,
    )
    participants = fields.ManyToManyField("app.User", related_name="lotteries", through="ticket")
    created_at = fields.DatetimeField(auto_now_add=True)
    modified_at = fields.DatetimeField(auto_now=True)

    tickets: fields.ReverseRelation["Ticket"]

    def __str__(self):
        return self.name

class Ticket(Model):
    """Many to many relationship between user and lottery"""

    id = fields.UUIDField(pk=True)
    user = fields.ForeignKeyField("app.User", related_name="tickets")
    lottery = fields.ForeignKeyField("app.Lottery", related_name="tickets")
    ticket_number = fields.IntField()
    created_at = fields.DatetimeField(auto_now_add=True)
    modified_at = fields.DatetimeField(auto_now=True)

    lotteries: fields.ReverseRelation["Lottery"]

    def __str__(self):
        return f"#{self.id} ({self.ticket_number})"

    class Meta:
        unique_together = ("ticket_number", "lottery")
long2ice commented 3 years ago

What's the version? I tried but no error.

ArtemBernatskyy commented 3 years ago

Just checked again, same error, latest tortoise version tortoise-orm==0.17.1 asyncpg==0.22.0 (postgresql latest from dockerhub)

  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/tortoise/backends/asyncpg/client.py", line 36, in translate_exceptions_
    return await func(self, *args)
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/tortoise/backends/asyncpg/client.py", line 176, in execute_query
    rows = await connection.fetch(*params)
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/asyncpg/connection.py", line 583, in fetch
    return await self._execute(
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/asyncpg/connection.py", line 1625, in _execute
    result, _ = await self.__execute(
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/asyncpg/connection.py", line 1650, in __execute
    return await self._do_execute(
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/asyncpg/connection.py", line 1677, in _do_execute
    stmt = await self._get_statement(
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/asyncpg/connection.py", line 375, in _get_statement
    statement = await self._protocol.prepare(
  File "asyncpg/protocol/protocol.pyx", line 166, in prepare
asyncpg.exceptions.UndefinedColumnError: column "total_tickets" does not exist

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/discord/ext/tasks/__init__.py", line 101, in _loop
    await self.coro(*args, **kwargs)
  File "/Users/artem/Desktop/LotteryBot/src/app/extensions/lottery.py", line 207, in lottery_status_cron_job
    await self._handle_payments_to_winners()
  File "/Users/artem/Desktop/LotteryBot/src/app/extensions/lottery.py", line 170, in _handle_payments_to_winners
    await Lottery.filter(Q(status=LotteryStatus.ENDED) & Q(has_winners=False))
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/tortoise/queryset.py", line 836, in _execute
    instance_list = await self._db.executor_class(
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/tortoise/backends/base/executor.py", line 124, in execute_select
    _, raw_results = await self.db.execute_query(query.get_sql())
  File "/Users/artem/Desktop/LotteryBot/src/env/lib/python3.9/site-packages/tortoise/backends/asyncpg/client.py", line 38, in translate_exceptions_
    raise OperationalError(exc)
tortoise.exceptions.OperationalError: column "total_tickets" does not exist