一种pythonic方式来解决以下实现

时间:2012-05-21 13:07:51

标签: django python django-orm

我的django应用程序中有3个模型

class Company(models.Model):

    name = models.CharField(_("Name"), max_length = 100, blank = True, null = True)
    address = models.CharField(_("Address"), max_length = 300, blank = True, null = True)

class WebSite(models.Model):

    WEBSITE_TYPE_CHOICES = (
        ('Google+', 'Google+'),
        ('Facebook', 'Facebook'),
        ('Orkut', 'Orkut'),
    )
    user = models.ForeignKey(User)
    website = models.URLField(blank = True, null = True)
    website_type = models.CharField(max_length = 15, choices = WEBSITE_TYPE_CHOICES, default = 'Google+')
    company = models.ForeignKey(Company, null=True, blank=True)

class Review(models.Model):

    rating = models.FloatField(blank = True, null = True) 
    review = models.TextField(blank = True, null = True)
    company = models.ForeignKey(Company, null=True, blank=True)
    website = models.ForeignKey(Website, null=True, blank=True)

我想显示我的数据,例如

公司A:

  1. Google - 5条评论,平均3.4
  2. Orkut - 9条评论,Avg 4.1
  3. Facebook - 12条评论,Avg 4.3
  4. Anyother - 2条评论,Avg 2
  5. CompanyB:

    1. Google - 2条评论,Avg 3
    2. Facebook - 5条评论,Avg 4
    3. 为此,我已经完成了

          final_list = company_list = []
          websites = Website.objects.select_related().filter(user = user)
      
          for website in websites:
              company = website.company
              if company is not None and company not in company_list:
                  company_list.append(brand)
                  company_websites = websites.filter(company = company)
                  info = []
                  for company_website in company_websites:
                      company_type = company_website.website_type
                      reviews = Review.objects.filter(company = company, website = company_website)
                      no_of_reviews = len(reviews)
                      average = reviews.aggregate(Avg('rating'))
                      info.append({"type": company_type, "no_of_reviews": no_of_reviews,
                                   "average": average['rating__avg']})
                  final_list.append({"company": company.name, "stats": info})
      

      代码存在2个问题

      1. 浪费了很多计算
      2. 它还以某种方式在final_list(BUGGY)
      3. 中附加空列表

        仅供参考:我相信.annotate()可以使用,但我无法理解如何根据列使用它,在我的例子中是(company__name)

2 个答案:

答案 0 :(得分:1)

这将为您提供数据。

Review.objects.values(company, website__website_type).annotate(review_count=Count('id'), average=Avg('rating')).order_by('company')

使用{% regroup %}将其输出到模板中。

答案 1 :(得分:0)

我没有测试过这个,它可能不如你收到的其他答案那么好,但万一它有帮助......

companies = Company.objects.all()
company_ratings = []

for company in companies:
    websites = company.website_set.filter(user=user)
    new_data = []

    for website in websites:
        reviews = Reviews.objects.filter(website=website, company=company)
        ratings = [x.rating for x in reviews]
        count = len(ratings)
        new_data.append({'website': website, 'count': count, 
                         'average': float(sum(ratings))/count})

    company_ratings.append({'company':company, 'ratings':new_data})