Django - 注释 price= "price_A" 或 "price_B"

Django - annotate price= "price_A" or "price_B"

我有多个字段存储来自不同来源的相同值类型(价格)。

class Product...
    price_amazon = ...
    price_ebay = ...
    price_etsy = ...

    @property
    def price...
        return self.price_amazon or self.price_ebay or self.price_etsy

我正在寻找一种方法来为查询集中的每个 Product 注释 price。它的行为应该与 price 属性.

完全一样

priceprice_amazonprice_ebayprice_etsy - 第一个不是 None 值。

你会怎么做?

我试过了:

Product.objects.all().annotate(price=F('price_amazon') or F('price_ebay') or F('price_etsy')) 

其中提出:

AttributeError                            Traceback (most recent call last)
~/PycharmProjects/.virtualenvs/.cloud/lib/python3.8/site-packages/IPython/core/formatters.py in __call__(self, obj)
    700                 type_pprinters=self.type_printers,
    701                 deferred_pprinters=self.deferred_printers)
--> 702             printer.pretty(obj)
    703             printer.flush()
    704             return stream.getvalue()

~/PycharmProjects/.virtualenvs/.cloud/lib/python3.8/site-packages/IPython/lib/pretty.py in pretty(self, obj)
    392                         if cls is not object \
    393                                 and callable(cls.__dict__.get('__repr__')):
--> 394                             return _repr_pprint(obj, self, cycle)
    395 
    396             return _default_pprint(obj, self, cycle)

~/PycharmProjects/.virtualenvs/.cloud/lib/python3.8/site-packages/IPython/lib/pretty.py in _repr_pprint(obj, p, cycle)
    698     """A pprint that just redirects to the normal repr function."""
    699     # Find newlines and replace them with p.break_()
--> 700     output = repr(obj)
    701     lines = output.splitlines()
    702     with p.group():

~/PycharmProjects/.virtualenvs/.cloud/lib/python3.8/site-packages/django/db/models/query.py in __repr__(self)
    261 
    262     def __repr__(self):
--> 263         data = list(self[:REPR_OUTPUT_SIZE + 1])
    264         if len(data) > REPR_OUTPUT_SIZE:
    265             data[-1] = "...(remaining elements truncated)..."

~/PycharmProjects/.virtualenvs/.cloud/lib/python3.8/site-packages/django/db/models/query.py in __len__(self)
    267 
    268     def __len__(self):
--> 269         self._fetch_all()
    270         return len(self._result_cache)
    271 

~/PycharmProjects/.virtualenvs/.cloud/lib/python3.8/site-packages/django/db/models/query.py in _fetch_all(self)
   1306     def _fetch_all(self):
   1307         if self._result_cache is None:
-> 1308             self._result_cache = list(self._iterable_class(self))
   1309         if self._prefetch_related_lookups and not self._prefetch_done:
   1310             self._prefetch_related_objects()

~/PycharmProjects/.virtualenvs/.cloud/lib/python3.8/site-packages/django/db/models/query.py in __iter__(self)
     74             if annotation_col_map:
     75                 for attr_name, col_pos in annotation_col_map.items():
---> 76                     setattr(obj, attr_name, row[col_pos])
     77 
     78             # Add the known related objects to the model.

AttributeError: can't set attribute

这就是 Coalesce [Django-doc] 的意义所在。您可以使用以下方式进行注释:

from django.db.models.functions import <b>Coalesce</b>

Product.objects.annotate(
    price=<b>Coalesce(</b>'price_amazon'<b>,</b> 'price_ebay'<b>,</b> 'price_etsy'<b>)</b>
)