Reputation: 979
Ok, so here is the deal. I'm working on this web-app that lets you create users, beers, and reviews for beers.
models.py:
from django.db import models
from django.conf import settings
class BeerModel(models.Model):
user = models.ForeignKey(User, default=1)
name = models.CharField(max_length=254, default="")
style = models.CharField(max_length=254, default="")
ibu = models.IntegerField(default="")
calories = models.IntegerField(default="")
abv = models.IntegerField(default="")
location = models.CharField(max_length=254, default="")
class Meta:
verbose_name_plural = 'Beers'
def __str__(self):
return self.name
def avg(self):
return
class RateModel(models.Model):
FIVE_REVIEWS = (
('5', '5'),
('4', '4'),
('3', '3'),
('2', '2'),
('1', '1'),
)
TEN_REVIEWS= (
('10', '10'),
('9', '9'),
('8', '8'),
('7', '7'),
('6', '6'),
('5', '5'),
('4', '4'),
('3', '3'),
('2', '2'),
('1', '1'),
)
user = models.ForeignKey(User, default=1)
beer = models.ForeignKey(BeerModel)
aroma = models.PositiveIntegerField(max_length=2, choices=FIVE_REVIEWS, default="5")
appearance = models.PositiveIntegerField(max_length=2, choices=FIVE_REVIEWS, default="5")
taste = models.PositiveIntegerField(max_length=2, choices= TEN_REVIEWS, default= "10")
class Meta:
verbose_name_plural = 'Ratings'
def __str__(self):
return str(self.beer)
As you can tell, you can create a review for different beers using different users.
My goal is to have django output on the HTML, an "Average" value for "Aroma, appearance, and taste" for each beer.
This is what I have in my views.py:
@login_required
def home(request):
beers = BeerModel.objects.order_by('name')
rates = RateModel.objects.order_by('user')
avg = RateModel.objects.aggregate(aroma = Avg('aroma'), appearance = Avg('appearance'), taste = Avg('taste'))
dict = {'records': beers, 'rates': rates, 'avg': avg}
return render(request, 'beer_tracker/home.html', context=dict)
This is what I have on my home.html:
<h2>Overall Rating</h2>
{% for beers in records %}
<div class="table">
<h4><b>Beer's Overall Ratings: </b>{{ beers.name}}</h4>
<ul>
<li><b>Aroma: </b>{{ avg.aroma }}</li>
<li><b>Appearance: </b>{{ avg.appearance }}</li>
<li><b>Taste: </b>{{ avg.taste }}</li>
</ul>
</div>
{% endfor %}
Unfortunately, as you can tell, I get the average for all beers. I need the average for each specific beer.
So if I have a beer, let's say Blue moon, and I have 2 users give 2 reviews:
User1 Aroma: 3, Appearance: 3, Taste: 8,
User2 Aroma: 5, Appearance: 5, Taste: 10,
I would like to get for Blue Moon:
Aroma: 4, Appearance: 4, Taste: 9,
But still keeping the reviews values for other beers independently.
Thank you for your time.
Anthony
Upvotes: 2
Views: 2335
Reputation: 308909
Instead of using aggregate, you should annotate your beers queryset with the averages.
from django.db.models import Avg
beers = BeerModel.objects.order_by('name').annotate(
avg_aroma=Avg('ratemodel__aroma'),
avg_appearance=Avg('ratemodel__appearance'),
avg_taste=Avg('ratemodel__taste'),
)
Then, when you loop through the beers queryset you can access the annotated fields.
{% for beer in beers %}
{{ beer.avg_aroma }}
{{ beer.avg_appearance} }
{{ beer.avg_taste }}
{% endfor %}
See the docs for joins and aggregates for more examples.
Upvotes: 3