0

Given a product (product_name is a parameter in the view), I am trying to return the 5 top-ranked products within that category (as defined by the method "get_avg_rating") as a list that I can loop through in a template. Any advice on how to do this?

class Productbackup(models.Model):
    website = models.CharField('Product name', max_length = 200)
    url_friendly = models.CharField('URL friendly', max_length = 200)
    website_url = models.URLField('Product URL')
    description= models.CharField('Description', max_length = 2000)
    category = models.ForeignKey(Categories)
    #category = models.ManyToManyField(Categories)
    image_hero = models.URLField('Hero image url')
    image_second = models.URLField('Second image url')
    image_third = models.URLField('Third image url')
    created_on = models.DateTimeField(auto_now_add = True)
    updated_at = models.DateTimeField(auto_now = True)
    def __unicode__(self):
        return self.website

    def get_avg_rating(self):
        reviews = Reviewbackup.objects.filter(product=self)
        count = len(reviews)
        sum = 0.0
        for rvw in reviews:
            sum += rvw.rating
        return (sum/count)

    def get_num_reviews(self):
        reviews = Reviewbackup.objects.filter(product=self)
        count = len(reviews)
        return count

RATING_OPTIONS = (
    (1, '1'),
    (2, '2'),
    (3, '3'),
    (4, '4'),
    (5, '5'),
                (6, '6'),
    (7, '7'),
    (8, '8'),
    (9, '9'),
    (10, '10'),
)
class Reviewbackup(models.Model):
    review = models.CharField('Review', max_length = 2000)
    created_on = models.DateTimeField(auto_now_add = True)
    updated_at = models.DateTimeField(auto_now = True)
    user = models.CharField('Username', max_length =  200)
    rating = models.IntegerField(max_length=2, choices=RATING_OPTIONS)
    product = models.ForeignKey(Productbackup)
    def __unicode__(self):
        return self.review

class Categories(models.Model):
    category = models.CharField('Category_second', max_length = 200)
        url_friendly = models.CharField('url_friendly', max_length = 200)
    def __unicode__(self):
        return unicode(self.category)

def view_reviews(request, product_name):
    product = get_object_or_404(Productbackup, url_friendly=product_name)
    product_id = product.id
    #get reviews for the this product
    reviews = Reviewbackup.objects.filter(product_id=product_id).order_by("-created_on")
    #similar products in category comparison
    prod_category = Productbackup.objects.filter(category=product.category)
    #top_ranked = Productbackup.objects.order_by('get_avg_rating')[0:5]
    #recently added
    recent_added = Productbackup.objects.order_by('-created_on')[0:5]
    return render_to_response('reserve/templates/view_reviews.html', {'prod_category': prod_category, 'product':product, 'reviews':reviews, 'recent_added':recent_added},
    context_instance=RequestContext(request))
sharataka
  • 5,014
  • 20
  • 65
  • 125

3 Answers3

0

Try to implement that:

Create a dictionary. It will have the Product as the key and the rating as the value.

Loop through your items (Product.objects)

In that loop, put each item in the dictionary

Out of that loop, sort the dictionary by value. (See Sort a Python dictionary by value)

Get the last items of the dictionary (dictionary[-5]).

Note that you will have to handle items with ex-aequo ratings. Indeed, if 10 items have the same score, then your Top 5 doesn't mean anything using the above method.

This would result in a code similar to this:

items_with_rating = {}
for product in Product.objects:
    items_with_rating[product] = product.get_avg_rating()

items_sorted_by_rating = sorted(items_with_rating.iteritems(), key=operator.itemgetter(1))

top5_items = items_sorted_by_rating[-5]
Community
  • 1
  • 1
tiktak
  • 1,214
  • 8
  • 15
  • the problem I'm finding with this solution is that the sorted dictionary (top5_items) doesn't allow me to access other attributes of product, such as description and category. It only returns a dictionary with the product name and rating. Any idea on how to access the other attributes in the template? – sharataka Jul 21 '12 at 19:19
  • I don't want to be rough but the problem is that you need to learn the basics of the Python language before playing with Django. The dictionary keys are your product OBJECTS, not strings. BTW, you should choose better class names. – tiktak Jul 23 '12 at 06:24
0

You can use annotate for that

from django.db.models import Sum, Avg

def get_top_products(amount=5):
    try:
         Productbackup.objects.annotate(review_amount=Sum("reviewbackup__product")).\
                               order_by("review_amount")[:amount]
    except Productbackup.DoesNotExist:
        return None

This is just a basic example, which can be extended to your needs

Hedde van der Heide
  • 21,841
  • 13
  • 71
  • 100
0

Maybe something like this could work?

products = [[prod, prod.get_avg_rating()] for prod in Productbackup.objects()]

top_5_items = sorted(products, key=lambda x: x[1], reverse=True)[:5]
Mikael
  • 3,148
  • 22
  • 20