Reputation: 43
I am creating a website that lets users post recipes. When the user clicks on a recipe they can see more details about it and they can also comment and give a rating. My question is how can I calculate the average recipe rating here
Models.py
class Recept(models.Model):
class NewManager(models.Manager):
def get_queryset(self):
return super().get_queryset()
naslov = models.CharField(max_length=100)
sestavine = models.CharField(max_length=100)
priprava = models.TextField()
rec_img = models.ImageField(upload_to='rec_pics', default='default2.jpg')
datum = models.DateTimeField(default=timezone.now)
avtor = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.PROTECT, default=1)
likes = models.ManyToManyField(
User, related_name="blog_recept", blank=True)
favorites = models.ManyToManyField(
User, related_name='favorite', default=None, blank=True)
newmanager = NewManager()
CHOICES = (
(1, '1 stars'),
(2, '2 stars'),
(3, '3 stars'),
(4, '4 stars'),
(5, '5 stars'),
)
class Reviews(models.Model):
recept = models.ForeignKey(
Recept, related_name="reviews", on_delete=models.CASCADE)
user = models.ForeignKey(
User, related_name="reviews", on_delete=models.CASCADE)
content = models.TextField(blank=True, null=True)
stars = models.IntegerField(choices=CHOICES)
datum = models.DateTimeField(default=timezone.now)
Views.py
class PostDetailView(FormMixin, DetailView):
model = Recept
form_class = CommentForm
def get_success_url(self):
return reverse('recept-detail', kwargs={'pk': self.object.id})
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
get_recept = get_object_or_404(Recept, id=self.kwargs['pk'])
fav = bool
if get_recept.favorites.filter(id=self.request.user.id).exists():
fav = True
total_sestavine = get_recept.vejice()
total_likes = get_recept.total_likes()
total_likes2 = get_recept.total_likes2() # pokliče functions
liked = False
if get_recept.likes.filter(id=self.request.user.id).exists():
liked = True
if get_recept.likes.exists():
last_like = get_recept.last_like()
context['last_like'] = last_like
else:
context['last_like'] = 0
context['total_likes'] = total_likes
context['total_likes2'] = total_likes2
context['liked'] = liked
context['fav'] = fav
context['total_sestavine'] = total_sestavine
context['form'] = CommentForm(
initial={'recept': self.object, 'user': self.request.user})
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.save()
return super(PostDetailView, self).form_valid(form)
So for example, if a recipe has 2 reviews and one review has 3 stars other has 5 stars the average would be 4.
Upvotes: 0
Views: 308
Reputation: 218
To calculate the average recipe rating for a given recipe, you can create a helper method like shown below:
from django.db.models import Avg
def calculate_average_rating(recipe):
average_rating = Reviews.objects.all().filter(recipe=recipe).aggregate(Avg('stars'))['stars__avg']
return average_rating
Explanation:
Django provides aggregate functions that we can use to extract average, maximum, minimum, etc. from a queryset. We have used the Avg
function. The aggregate function Avg
returns the average as a form of dictionary: {'stars__avg': 4}
for example. To extract the actual value from the returned dictionary, we have appended ['stars__avg'] at the end.
Upvotes: 1