[Django]-Django Python โ€“ Itertools is not aligning products with sum of auction sales

1๐Ÿ‘

If youโ€™re not stuck on itertools, but want to do this the Django way, then use:

views.py:

post_field_name = Post._meta.get_field('product').related_query_name()
field_ref = f"{post_field_name}__auctionsale"
sales = Product.objects.annotate(total_sales=Sum(field_ref))

template.html (sales queryset passed as "sales" variable to template):

<table>
    {% for sale in sales %}
        <tr><td>{{ sale.sku }}</td><td>{{ sale.total_sales|default_if_none:"$ 0" }}</td></tr>
    {% endfor %}
</table>
๐Ÿ‘คuser1600649

1๐Ÿ‘

I would rather use the Coalesce(...)โ€“(Django Doc) database function of Django along with the Sum()โ€“(Django Doc) function

from django.db.models import Sum
from django.db.models.functions import Coalesce

product_qs = Product.objects.annotate(
    action_sum=Coalesce(Sum("post__auctionsale"), 0)
                                                ^^^^^ this is the default value
)
for product in product_qs:
    print(product.sku, " ---- ", product.action_sum)

# Result
30  ----  400
10  ----  0
20  ----  0
40  ----  0
๐Ÿ‘คJPG

0๐Ÿ‘

The issue lies with your use of itertools.zip_longest(products, posts, fillvalue='0'), as only one of your items has had a sale, posts has only one item, and itertools.zip_longest associates this item to the first one of products, which happens to be sku 10.

To fix this, you can use a dictionnary for your posts that associates the posts to their product :

posts = {post.product: post.total for post in Post.objects.filter(product__sku__in=products.values('sku'), product__entity=entityquery, product__period=periodquery).annotate(total=Sum('auctionsale'))}

Then, to construct your list, you can define a function :

def mk_list(products, posts):
  values = []
  for product in products:
    values.append((product, posts.get(product, 0)))
  return values

When a product has no auction sales associated to it, posts.get(product, 0) will return 0, which is what you need.

๐Ÿ‘คTom Hubrecht

Leave a comment