Django Annotation F() value

У меня есть вопрос относительно аннотаций Django:

tickers = {
    "BCO": 10.0,
    "AIR": 50.0,
}

assets = Asset.objects.annotate(
    price=(tickers[F("fk_security__ticker_symbol")]))

Я хотел бы аннотировать значение из словаря к активу, но всегда получаю ошибку ключа: F(fk_security__ticker_symbol)

Что я делаю не так? Возможно ли это вообще сделать? Заранее большое спасибо!

Если это поможет, вот моя модель:

class Asset(models.Model):
    fk_security = models.ForeignKey(Security, on_delete=models.CASCADE, blank=False, verbose_name="Security",related_name="security",
    )

class Security(models.Model):
    ticker_symbol = models.CharField(
        max_length=5,
        verbose_name="Ticker Symbol",
        default="",
    )

Если вам не нужно фильтровать, агрегировать или что-то еще по цене, я бы посоветовал не делать это в ORM, поскольку JOINing с словарем будет медленным и сложным.

Так что мы можем сделать это с помощью:

tickers = {
    'BCO': 10.0,
    'AIR': 50.0,
}

assets = Asset.objects.select_related('fk_security')
for asset in assets:
    asset.price = tickers.get(asset.fk_security.ticker_symbol)

иначе мы можем использовать:

from django.db.models import Case, Value, When

Asset.objects.annotate(
    price=Case(
        *[
            When(fk_security__ticker_symbol=k, then=Value(v))
            for k, v in tickers.items()
        ]
    )
)

Но оба варианта - не хорошая идея. Лучший способ - работать с моделью, хранящей цены, и делать JOINы.


Note: Normally one does not add a prefix fk_… to a ForeignKey field, since Django will automatically add a "twin" field with an …_id suffix. Therefore it should be security, instead of fk_security. You can use the db_column=… parameter [Django-doc] to specify the name of the column in the database if you want to name this differently from the field name.

Вернуться на верх