How can I find how much 1 star/2 star----5star present in percentage? - django

I've created a form for being stored ratings and feedback in the database. Ratings and Feedback are being stored in the database perfectly. But the problem is, I can't find out how many different types of rating stars are present in the database. How can I find out how many 1 star/2star/---5 stars are present in the object model in percentage? What should I do?
models.py:
class Frontend_Rating(models.Model):
USer = models.ForeignKey(User,default=None,on_delete=models.CASCADE, related_name="frontend_rating")
Rating = models.IntegerField(null=True)
Feedback = models.TextField(max_length=250, null=True)
def __str__(self):
return str(self.pk)+ str(".") + str(self.USer) + str("(") + str(self.Rating) + str("stars") +str(")")
Views.py:
def index(request):
#rating____________________
frontend_all_ratings = Frontend_Rating.objects.all()
number_of_frontend_rating = frontend_all_ratings.count()
average_rating = 0
frontend_one_star = 0
frontend_two_star = 0
frontend_three_star = 0
frontend_four_star = 0
frontend_five_star = 0
percentage_frontend_ONE_star = 0
percentage_frontend_FIVE_star = 0
for frontend_rating_item in frontend_all_ratings:
frontend_rating = frontend_rating_item.Rating
if frontend_rating:
total_ratings = 0
total_ratings += frontend_rating
average_rating = round(total_ratings/frontend_all_ratings.count(),1)
context = {
"frontend_five_star":frontend_five_star,
"frontend_one_star":frontend_one_star,
"total_ratings":total_ratings,
"average_rating":average_rating,
}
return render(request,'0_index.html',context)

You can obtain the data with a single query with:
from django.db.models import Avg, BooleanField, ExpressionWrapper, Q
data = Frontend_Rating.objects.aggregate(
frontend_one_star=Avg(ExpressionWrapper(Q(Rating=1), output_field=BooleanField())),
frontend_two_star=Avg(ExpressionWrapper(Q(Rating=2), output_field=BooleanField())),
frontend_three_star=Avg(ExpressionWrapper(Q(Rating=3), output_field=BooleanField())),
frontend_four_star=Avg(ExpressionWrapper(Q(Rating=4), output_field=BooleanField())),
frontend_five_star=Avg(ExpressionWrapper(Q(Rating=5), output_field=BooleanField())),
)
frontend_one_star = data['frontend_one_star']
frontend_two_star = data['frontend_two_star']
frontend_three_star = data['frontend_three_star']
frontend_four_star = data['frontend_four_star']
frontend_five_star = data['frontend_five_star']
or for databases that use integer division, like postgresql:
from django.db.models import Count, FloatField, Q
data = Frontend_Rating.objects.aggregate(
frontend_one_star=Count('pk', filter=Q(Rating=1), output_field=FloatField()) / Count('pk', output_field=FloatField()),
frontend_two_star=Count('pk', filter=Q(Rating=2), output_field=FloatField()) / Count('pk', output_field=FloatField()),
frontend_three_star=Count('pk', filter=Q(Rating=3), output_field=FloatField()) / Count('pk', output_field=FloatField()),
frontend_four_star=Count('pk', filter=Q(Rating=4), output_field=FloatField()) / Count('pk', output_field=FloatField()),
frontend_five_star=Count('pk', filter=Q(Rating=5), output_field=FloatField()) / Count('pk', output_field=FloatField()),
)
frontend_one_star = data['frontend_one_star']
frontend_two_star = data['frontend_two_star']
frontend_three_star = data['frontend_three_star']
frontend_four_star = data['frontend_four_star']
frontend_five_star = data['frontend_five_star']
Note: Models in Django are written in PascalCase, not snake_case,
so you might want to rename the model from Frontend_Rating to FrontendRating.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: rating instead of Rating.

number_of_frontend_rating = Frontend_Rating.objects.count()
# Divide value by overall count to get ratio and multiply ratio by 100 to get percentage
frontend_one_star = (Frontend_Rating.objects.filter(Rating=1).count() / overall_count)*100
frontend_two_star = (Frontend_Rating.objects.filter(Rating=2).count() / overall_count)*100
frontend_three_star = (Frontend_Rating.objects.filter(Rating=3).count() / overall_count)*100
frontend_four_star = (Frontend_Rating.objects.filter(Rating=4).count() / overall_count)*100
frontend_five_star = (Frontend_Rating.objects.filter(Rating=5).count() / overall_count)*100
Please correct me if I misunderstood your question

Related

How to return calculations to a template for all objects in a class model in Django

I am trying to build a simple form which calculates which machine would run a film width the quickest, the parameters and capabilities of each machine are held in a django model.
The width of the film and how much of it will be entered in the form and the quantity needed. The function should work out which machine(s) can run it, what the max speed is and the average speed over the machines that are capable.
I want to return the values of the calculation and maybe run a for loop and display the values for each machine in a results.html template in a table. I also want to display average times across machines capable of running the widths of film.
I had some success with lists but would like to use a class that I can use in the template and do away with the lists.
Any help with this would be much appreciated as I am getting pretty lost in it!
I have only started on the 'Layflat Tubing' function in the hope that I can get it right and just copy down to the other functions.
from django.views.generic.base import TemplateView
from django.shortcuts import render
import math, datetime
from settings.models import Extruder
class Result:
def __init__(self, ext_no, width, speed=0, ):
self.ext_no = ext_no
self.width = width
self.speed = speed
def __str__(self):
return self.ext_no
extruders = Extruder.objects.all()
class FilmSpeedView(TemplateView):
template_name = 'calculations/film-speed.html'
class BagWeightView(TemplateView):
template_name = 'calculations/bag-weight.html'
class CalculatorsView(TemplateView):
template_name = 'calculations/calculators.html'
def result(request):
film_type=''
film_width=''
measure=''
speeds = [0]
quantity = 0
max_speed = 0
ave_speed = 0
ave_time = 0
max_time = 0
a=[]
b=[]
c=[]
d=[]
e=[]
if request.method=="GET":
film_type = str(request.GET["film_type"])
film_width = int(request.GET["film_width"])
edge_trim = int(request.GET["edge_trim"])
quantity =int(request.GET["quantity"])
measure = str(request.GET["measure"])
if measure == "metric":
film_width = int(film_width)
else:
film_width = film_width * 25.4
if edge_trim is None:
edge_trim = 0
else:
edge_trim = int(edge_trim)
if str(film_type) == 'Layflat Tubing':
film_type = "LFT"
for extruder in extruders:
bur = film_width / extruder.die_size
if film_width < extruder.min_width:
b.append(extruder.name + ' : Film too narrow')
extruder = Result(ext_no = extruder.ext_no, width = 'too narrow')
elif film_width > extruder.max_width:
b.append(extruder.name + ' : Film too wide')
extruder = Result(ext_no = extruder.ext_no, width = 'too wide')
else:
percentage = film_width / extruder.max_width
speed = extruder.max_kgs_hr * percentage
extruder = Result(ext_no = extruder.ext_no, speed = round(extruder.max_kgs_hr * percentage, 2), width = 'ok')
speeds.append(speed)
max_speed = max(speeds)
ave_speed = sum(speeds) / len(speeds)
ave_time = float(quantity) / ave_speed * 60.0
max_time = float(quantity) / max_speed * 60.0
else:
film_type = "Invalid Film Type"
m = a
n = b
o = c
g = str(round(ave_speed, 2)) + 'kg\'s/h'
h = str(datetime.timedelta(minutes=ave_time))
i = str(datetime.timedelta(minutes=30))
j = str(round(max_speed, 2)) + 'kg\'s/h'
k = str(datetime.timedelta(minutes=max_time))
return render(request, 'calculations/result.html', {'a':a, 'b':b, 'c':c, 'd':d, 'e':e, 'g':g, 'h':h, 'i':i, 'j':j, 'k':k, 'm':m, 'n':n, 'o':o, 'bur':bur,})

in django ,how to sum a int field and two float field in jsonb using postgresql

I have a model like this:
class Priority(models.Model):
base = models.FloatField(default=0)
job = models.JSONField()
users = models.JSONField()
and both job and users are similar.
like job = {'a':1,'b':2}, user = {'c':3,'d':4}
I want to get the sum ( base + job__a + users__c)
how can I write the filter statement,
and raw sql is fine too.
Thanks
You should accomplish this (updated):
queryset = Priority.objects.annotate(
a=Coalesce(
Cast(KeyTextTransform('a', 'job'), output_field=FloatField()),
Cast(V(0.0), output_field=FloatField())
),
c=Cast(KeyTextTransform('c', 'users'), output_field=FloatField()),
).annotate(
sum=Sum(
F('base') + F('a') + F('c'), output_field=FloatField()
)
)
for item in queryset:
print(item.sum)

Django Calculate Mean Of 2 Fields Inside Multiple Objects

I'm trying to do a very simple math problem but I don't know how to convert it into python. Basically I need to calculate the mean entry price for a trade based on multiple "buy" entries. To do that all one needs to do is calculate
∑ (entry.amount * entry.price) / ∑ (entry.amount)
This should be the variable "total_entry_price2" in the end.
Where am I going wrong with the calculation? How Can I add all the ∑'s together?
Is this the best way to do it?
models.py
class Trade(models.Model):
...
class Entry(models.Model):
...
trade = models.ForeignKey(Trade, on_delete=models.CASCADE)
amount = models.FloatField()
price = models.FloatField()
entry_type = models.CharField(max_length=3, choices=ENTRY_TYPE_CHOICES, default=BUY)
views.py
#login_required
def trade_detail_view(request, pk):
logger.info('trade detail view')
if request.method == 'GET':
trade = get_object_or_404(Trade, pk=pk)
entries = Entry.objects.filter(trade=trade)
entries_buy = Entry.objects.filter(trade=trade, entry_type="buy")
patterns = Pattern.objects.filter(trade=trade)
for entry in entries_buy:
total_entry_price = Sum(entry.amount * entry.price)
total_entry_price2 = total_entry_price / entries_buy.aggregate(Sum('amount'))
print(total_entry_price2)
context = {
'trade': trade,
'entries': entries,
'patterns': patterns,
'max_amount': entries_buy.aggregate(Sum('amount')),
'total_fees': entries.aggregate(Sum('fee')),
'entry_price': entries_buy.aggregate(Avg('price'))
}
Current Terminal print:
Sum(Value(60.0)) / Value({'amount__sum': 40.0})
Sum(Value(10.0)) / Value({'amount__sum': 40.0})
Example data
The correct answer should be $1.75
(30 * 2 + 10 * 1) / 40 = 1.75
Final Solution (added upon from Oleg Russkin's Answer)
The revisions I did are as follows:
total_entry_cost = entries_buy.annotate(
s=F('amount') * F('price')
).aggregate(
total_entry_cost=ExpressionWrapper(
Sum(
Cast('s', output_field=models.FloatField())
) / Sum('amount'),
output_field=models.FloatField()
)
)['total_entry_cost']
print(total_entry_cost)
Example query to calculate required value.
Cast() to float may be avoided if the result of Sum is float, not an integer.
from django.db import models
from django.db.models import ExpressionWrapper, F, Sum
from django.db.models.functions import Cast
total_entry_price2 = Entry.objects.annotate(
s=F('amount')+F('price')
).aggregate(
price2=ExpressionWrapper(
Sum(
Cast('s',output_field=models.FloatField())
) / Sum('amount'),
output_field=models.FloatField()
)
)['price2']
# Actual result of the query is dictioanry
# so we get the key
# {'price2': 0.59633706227207}
Updated Answer By OP
This answer almost got us all the way. It was my fault not to be more clear on the exact answer I was looking for. I updated my question near the end to reflect it.
The revisions I did are as follows:
total_entry_cost = entries_buy.annotate(
s=F('amount') * F('price')
).aggregate(
total_entry_cost=ExpressionWrapper(
Sum(
Cast('s', output_field=models.FloatField())
) / Sum('amount'),
output_field=models.FloatField()
)
)['total_entry_cost']
print(total_entry_cost)

how to use track_visibility=always and store=true with compute field?

Here, i need the actual sales at the side of crm opportunity.
I had done all computation part but, not store that value with
track_visibility='always' and store=True.
from odoo import api,fields,models,_
class CrmLead(models.Model):
_inherit = "crm.lead"
actual_sales = fields.Float(string="Actual Sales", store=True, compute="compute_actual_sales", track_visibility='always')
#api.depends('order_ids')
def compute_actual_sales(self):
for record in self:
total_actual_sales_amount_in_opp = 0
for order in record.order_ids:
if order.state == 'sale':
sales_amount_in_opp = order.amount_total
print">>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<sales_amount_in_opp>>>>>>>>>>>>>>><", sales_amount_in_opp
total_actual_sales_amount_in_opp = order.amount_total + total_actual_sales_amount_in_opp
print">>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<total_sales_amount_in_opp>>>>>>>>>>>>>>><", total_actual_sales_amount_in_opp
record.actual_sales = total_actual_sales_amount_in_opp

Django query using filters

I have 3 models in django:
class Movie(models.Model):
mid = models.IntegerField(primary_key = True)
name = models.CharField(max_length = 100)
class User(models.Model):
username = models.CharField(max_length=128, null=True)
uid = models.CharField(max_length=100)
movie = models.ManyToManyField(Movie, through = "Vote")
class Vote(models.Model):
movie = models.ForeignKey(Movie)
user = models.ForeignKey(User)
rating = models.IntegerField()
here rating = 0/1, 0 means dislike, 1 means like
i want to make some queries using filters:
find out all movies that a current user likes. For that i use this following 2 queries, but none of them work. In both cases it gives erroneous results
ans = Movie.objects.filter(vote__user = self).filter(vote__rating = 1)
ans = Movie.objects.filter(user__uid = self.uid).filter(vote__rating = 1)
I have a list of users in an array ids. I want to find out how many users from this list like a particular movie?
i tried this, but this is also incorrect:
ret = User.objects.filter(uid__in = ids).filter(vote__movie = mov).filter(vote__rating = 1)
can somebody please help me with these 2 queries?
I'd also suggest letting django assign the model's id's but if you are using a legacy database or for some other reason need to assign the id's you can query like so:
# uid is some uid
user = User.objects.get(uid=uid)
likes = Movie.objects.filter(vote__user=user, vote__rating=1)
or
likes = Movie.objects.filter(vote__user__uid=some_uid, vote__rating=1)
count of people in the list of users who like a specific movie:
>>> uids = ['1','2','3']
>>> # if mov is a Movie instance
>>> votes = Vote.objects.filter(user__uid__in=uids, movie=mov, rating=1)
>>> print votes.query
SELECT "so1_vote"."id", "so1_vote"."movie_id", "so1_vote"."user_id", "so1_vote"."rating" FROM "so1_vote" INNER JOIN "so1_user" ON ("so1_vote"."user_id" = "so1_user"."id") WHERE ("so1_user"."uid" IN (1, 2, 3) AND "so1_vote"."movie_id" = 1 AND "so1_vote"."rating" = 1 )
>>> # if mov is a mid for a movie
>>> # get movie instance by using Movie.objects.get(mid=mov)
>>> # or query:
>>> # votes = Vote.objects.filter(user__uid__in=uids, movie__mid=mov, rating=1)
>>> likes_count = votes.count()
>>> print likes_count
0
combined:
likes_count = Votes.objects.filter(user__uid__in=uids, movie=mov, rating=1).count()