【问题标题】:Django get a value for annotated field based on condition?Django根据条件获取注释字段的值?
【发布时间】:2022-01-25 19:32:22
【问题描述】:

我有几个简单的模型,想用基于条件的字段来注释查询。

    class Book(models.Model):
        price = models.DecimalField('Price', null=True, default=None, max_digits=32, decimal_places=2)
        ...

    class Config(models.Model):
        city_prices = models.JSONField(default={"Paris": 10, "London": 15}, null=True)
        ...

我尝试这样查询这个模型:

from django.db.models import F, When, Case, Subquery

config = Config.objects.first()

Book.objects.annotate(custom_price=Case(
    When(price__isnull=False, then=F('price')),
    When(price__isnull=True, then=Subquery(config.city_prices.get(F('city'))))
)

我尝试使用 OuterRef 代替 F(),但它也没有成功。第一个“When”效果很好,但第二个在两种情况下都让我出错,使用 F() 或 OuterRef()

When(price__isnull=True, then=Subquery(db_conf.get(OuterRef('city'))))

AttributeError: 'NoneType' object has no attribute 'all'

我尝试在第二个“When”和核心城市名称中去掉“F()”,但又出现了一个错误。

When(price__isnull=True, then=Subquery(config.city_prices.get('London')))

AttributeError: 'int' object has no attribute 'all'

此错误表明我得到了“伦敦”的值,但子查询尝试查询它。所以我得出一个结论,当在之前的查询中我尝试使用“F('city')”时,它返回了 None,我认为这是因为 F('city') 指的是 Config 模型而不是 Book。

我尝试了不同的方法,但也不成功。

>>>from django.db.models.expressions import RawSQL
>>>Books.objects.annotate(custom_price=RawSQL('SELECT d.city_prices ->> %s FROM CONFIG_CONFIG d WHERE d.id = 1', (F('price'),)))

ProgrammingError: can't adapt type 'F'

我在这里读到 F() 不能与 RawSQL 协作。认为问题是我在查询结束时得到 dict 并希望从中提取值。那么如何实现我的目标,即根据条件为带注释的字段获取值?

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    第一种方法:在应用程序上计算custom_price。它更简单,但您不能通过custom_price订购书籍

    from django.db.models import F, When, Case, Subquery
    
    config = Config.objects.first()
    
    
    books = list(Book.objects.all())
    
    for book in books:
        if book.price is not None:
            book.custom_price = book.price
        else:
             book.custom_price = config.city_prices.get(book.city)
             
    

    第二种方法:计算config.city_prices的Case-When表达式并标注:

    from django.db.models import F, When, Case, Subquery, Value
    
    config = Config.objects.first()
    
    whens = []
    
    for city, price in config.city_prices.items():
        whens.append(When(city=city, then=Value(price)) 
    
    Book.objects.annotate(custom_price=Case(*whens))
             
    

    【讨论】:

    • 太好了,第二种情况正是我想要的!在问题之前,我考虑了第一个,但我看起来它不像 Case/When 那样有效。所以,无论如何,非常感谢!
    猜你喜欢
    • 2018-04-06
    • 1970-01-01
    • 2014-11-01
    • 2019-05-25
    • 2023-04-03
    • 2011-10-23
    • 2015-10-21
    • 2018-11-28
    • 2018-05-29
    相关资源
    最近更新 更多