在仍然可以访问外来对象的同时注释总和

时间:2017-02-10 03:04:04

标签: django

假设我有一个带这些模型的简单购物车系统:

from django.db import models
from django.utils import timezone


class Product(models.Model):
    name = models.CharField(max_length=255)
    # More fields...

    @property
    def featured_image(self):
        try:
            return self.productimage_set.all()[0]
        except IndexError:
            return None

    def __str__(self):
        return self.name


class ProductImage(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    image = models.FileField(upload_to='products/')
    # More fields...

    def __str__(self):
        return self.product.name


class Order(models.Model):
    created = models.DateTimeField(default=timezone.now)
    # More fields...

    def __str__(self):
        return str(self.pk)


class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()
    # More fields...

    def __str__(self):
        return 'Order %s: %s of %s' % (
            self.order_id,
            self.quantity,
            self.product.name,
        )

当用户下订单时,会为他们订购的每件商品创建一个OrderItem对象,这让我知道(1)他们购买了哪种产品,以及(2)他们购买了多少产品。

现在,假设我想向用户显示他们最常订购的产品。我将以此数据为例:

Order 1:
Product A: 10

Order 2:
Product A: 10
Product B: 5

Order 3:
Product A: 10
Product B: 5
Product C: 5

此特定用户应按此顺序显示产品:

Product A: 30 total
Product B: 10 total
Product C: 5 total

这是实现此目的的代码:

order_items_by_quantity = OrderItem.objects.values(
    'product__name',
).annotate(
    total_purchased=Sum('quantity'),
).order_by(
    '-total_purchased',
)

for order_item in order_items_by_quantity:
    print(order_item)

但是使用这种方法,我无法使用order_item.product.featured_image。有没有办法可以同时拥有这两种东西?也就是说,所有数量都是从大多数到最少总结和排序的使用order_item.product.featured_image的能力。

2 个答案:

答案 0 :(得分:0)

nesterovs_momentum

答案 1 :(得分:0)

我认为在使用values()之后有一种获取对象属性的方法,因为查询集返回带有SELECT键值的dicts,而不是模型对象。您可以执行其他查询以获取包含精选图片的产品,并将其映射到order_items

order_items_by_quantity = OrderItem.objects.values(
    'product__name', 'product_pk'
).annotate(total_purchased=Sum('quantity')).order_by('-total_purchased')

product_image_map = {}
for product in Product.objects.prefetch_related('productimage_set'):
    product_image_map[product.pk] = product.featured_image

for order_item in order_items_by_quantity:
    order_item['featured_image'] = product_image_map[order_item['product_id']]

这样你就可以向数据库询问一次产品,而不是每次迭代order_items_by_quantity。此外,您应该对图片进行prefetch_related()