Question

Say I have a model like

class Product(models.Model):
    name = models.CharField(max_length=64)
    [...]

and another like

class Price(models.Model):
    product = models.ForeignKey('Product')
    date = models.DateField()
    value = models.FloatField()
    [...]

and I want to display products in a modelAdmin, with the last price registered in a column.

So far, the only way I have found is to add the following method to the product object:

@property
def last_price(self):
    price = Price.objects.filter(product=self.pk).order_by("-date")
    return price[0].value if price else None

and then adding last_price to the list_display in Product's ModelAdmin. I don't like this approach because it ends up doing a query for each row displayed.

Is there a better way to do this in code?. Or do I have to create a column in the Product table and cache the last price there?.

Thanks!

Was it helpful?

Solution 2

A cleaner version of what you have would be:

def last_price(self):
    latest_price = self.price_set.latest('date')
    return latest_price.value if latest_price else None

But this still involves queries for each item.

You if you want to avoid this I would suggest adding a latest_price column to Product. Then you could set up a post_save signal for Price that then updates the related Product latest_price (This could be a ForiegnKey or the value itself.)

Update

Here is a receiver that would update the products latest price value when you save a Price. Obviously this assumes that you are saving Price models in chronological order so the lastest one saved is the latest_value

@receiver(post_save, sender=Price)
def update_product_latest_value(sender, instance, created, **kwargs):
    if created:
        instance.product.latest_value = instance.value
        instance.product.save()

OTHER TIPS

to reduce the the queries for each entry use the following:

Price.objects.filter(product=self.pk).order_by("-date").select_related('product')

this will decrease the product query at each object, hope it is helpful, vote up please

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top