pkdkk
pkdkk

Reputation: 3963

Django prefetch_related in loop, what is wrong?

i am trying to reduce the amount of queries in a Django app, but can't figure out how to do it the right way. I have a model with product all products has a default price, now I have a customerproduct with some customer related product prices

I am open for a redesign ;)

class Product(models.Model)
    name = models.CharField(max_length=255)
    price = models.DecimalField(default=0, max_digits=12, decimal_places=2)
    ....

    def get_prices(self, customer=None):
        '''
        get prices for the current product based on the price matrix given by bbp
        '''
        if customer:
            prices = self.get_customer_prices()
            if prices:
                self.price = self.customerproduct_set.filter(deleted=0).last().price

        return self

class CustomerProduct(AbstractProductPrice):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    price = models.DecimalField(default=0, max_digits=12, decimal_places=2)
    ....

Now i want all products with related customer prices.

products = Product.objects.all().prefetch_related('customerproduct_set')

    for product in products:
        product.get_prices(customer=1)

Prefetch is not "working" i don't understand how to use it.. please help.

I have 31 products in my db and django_debug_tool result in 35 queries.

Upvotes: 1

Views: 1079

Answers (1)

Todor
Todor

Reputation: 16010

Prefetch CustomerProducts only for the customer you are interested in, then work with that result. Something like that:

products = Product.objects.all().prefetch_related(
    models.Prefetch(
        'customerproduct_set',
        queryset=CustomerProduct.objects.filter(customer=customer, deleted=0).order_by('id')
        to_attr='customer_prices'
    )
)

def get_product_prices(product):
    customer_prices = getattr(product, 'customer_prices', None)
    if customer_prices:
        return customer_prices[-1].price
    return product.price


for product in products:
    print get_product_prices(product)

Upvotes: 2

Related Questions