Query to fetch highest rated movie with mimimum 5 people rated - python

I want to fetch name of movie with maximum rated movie with minimum 5 people rated in django.
My code :
model.py
class Movie(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
vote_count = models.IntegerField()
class Watchlist(models.Model):
userid = models.IntegerField()
movie_id = models.ForeignKey(Movie, on_delete=models.CASCADE)
rating = models.IntegerField()
what will be query to get movie with highest rating with minimum 5 people ?

I propose that you make some changes to your model. Normally ForeignKeys do not end with an id suffix, since Django will add a "twin field" with an _id suffix that stores the value of the target field. Furthermore you probably better make a ForeignKey to the user model. If you do not specify a primary key yourself, Django will automatically add an field named id that is an AutoField, hendce there is no need to add that manually. Finally you do not need to store the vote_count in a field of the Movie, you can retrieve that by counting the number of related Rating objects:
from django.conf import settings
class Movie(models.Model):
title = models.CharField(max_length=100)
class Rating(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete.models.CASCADE)
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
rating = models.IntegerField()
Then we can retrieve the highest rated movie with:
from django.db.models import Avg, Count
higest_rated = Movie.objects.annotate(
rating=Avg('rating__rating'),
votes=Count('rating')
).filter(votes__gte=5).order_by('-rating').first()
Here the votes__gte=5 will filter such that it will only obtain Movies with five or more votes, and we order by rating in descending order.

I'd modify the model, moving out Rating entity related fields from Watchlist and Movie.
Add the "Rate" class, and then filter by two conditions:
Count(Rate for the exact Movie) > minimum threshold(e.g. 5)
AVG(rating score for the exact Movie) > minimum threshold(e.g. 5)
or, if you need top-rated movies, use Order by as it described in that answer
In your case, you could use Count and Average with Watchlist.Rating field

Related

Django: Get average rating per user

Given the following, how can I make a query which returns a list of the average rating per user in friendlist?
models.py
class Beer(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.CharField(max_length=150)
...
class Checkin(models.Model):
id = models.IntegerField(primary_key=True)
rating = models.FloatField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=CASCADE)
...
class FriendList(models.Model):
user = models.OneToOneField(User, on_delete=CASCADE, primary_key=True)
friend = models.ManyToManyField(User, related_name="friends")
database (postgresql)
user
beer
rating
1
1
4.2
1
1
3.5
1
1
4.0
2
1
4.1
2
1
3.7
My current query to get all friends checkins:
Checkin.objects.filter(beer=1, user__in=friends.friend.all())
Which gives me something like:
[{user: 1, rating: 4.2}, {user: 1, rating: 3.5},...,{user: 2, rating: 4.1}...]
What I want is:
[{user: 1, avg_rating: 4.1}, {user: 2, avg_rating: 3.8}]
It makes more sense to .annotate(…) [Django-doc] the User objects, so:
from django.db.models import Avg
friends.friend.filter(
checkin__beer_id=1
).annotate(
rating=Avg('checkin__rating')
)
Where checkin__ is the related_query_name=… [Django-doc] for the user from Checkin to the User model. If you did not specify a related_query_name=…, then it will use the value for the related_name=… [Django-doc], and if that one is not specified either, it will use the name of the source model in lowercase, so checkin.
The User objects that arise from this queryset will have an extra attribute .rating that contains the average rating over the Checkins for that beer_id.
You can determine the average of these averages with an .aggregate(…) call [Django-doc]:
from django.db.models import Avg
friends.friend.filter(
checkin__beer_id=1
).annotate(
rating=Avg('checkin__rating')
).aggregate(
all_users_avg_rating=Avg('rating'),
number_of_users=Count('pk')
)
This will return a dictionary with two elements: all_users_avg_rating will map to the average of these averages, and number_of_users will return the number of distinct users.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Count & Sum of Order Values for each customer (through iteration) in Django

I have Customer & Order models as below:
class Customer(models.Model):
name = models.CharField(max_length = 100)
city = models.CharField(max_length = 100)
class Order(models.Model):
value = models.FloatField()
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
Now I would like to generate a table of (distinct) customers along with a count of number of orders placed by each of them and the sum of values of those orders. I tried this in the views.py:
def customers(request):
customer_orders = Order.objects.distinct().annotate(Sum('value'))
Then in my html template, I tried the following:
<ul>
{% for customer in customer_orders %}
<li>{{customer.customer}} - {{customer.value__sum}}<li>
{% endfor %}
</ul>
After all this, instead of getting unique customers (and respective order records), I'm getting a list of all orders and customers are getting repeated (as shown below). Not sure what I'm missing here.
Bosco-Ward - 16,700.0
Ernser PLC - 51,200.0
Murphy Ltd - 21,400.0
Kohler-Veum - 29,200.0
Schmidt-Legros - 96,800.0
Brown-Weissnat - 8,200.0
Bosco-Ward - 36,400.0
Ernser PLC - 66,600.0
Murphy Ltd - 84,200.0
Also wanted to know if there's a possibility to generate a table of city names with order count and total value of orders received from that city (note that my order model doesn't have city field).
Since you want a queryset of Customer instances make your query on the Customer model itself instead of on Order, next I believe you will not need to use distinct here since the customer instances should be considered unique. Hence, you can make a query like:
from django.db.models import Count, Sum
customers = Customer.objects.annotate(order_count=Count('order'), order_value_sum=Sum('order__value'))
for customer in customers:
print(customer.name, customer.order_count, customer.order_value_sum)
Kindly note im typing the solution from my phone without testing it but this is what i think:
Give a related name to customer in Order model:
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name=“orders”)
Get orders count:
Customer.objects.get(id=1).orders.count()
Or access this attribute in template something like:
{{ customer.orders.count }}
Get orders count values by city
From django.db.models import Count, Sum
Customer.objects.values(“city”).annotate(order_count=Count(“orders”)).annotate(totals=Sum(“value”))
Add realted_name to Order customer field:
class Customer(models.Model):
name = models.CharField(max_length = 100)
city = models.CharField(max_length = 100)
class Order(models.Model):
value = models.FloatField()
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='orders')
query:
Customer.objects.values(“city”).annotate(order_count=Count(“orders”)).annotate(totals=Sum(“orders__value”))

Django form list field or json field?

I have a model called participants as below
class participants(models.Model):
username= models.CharField(max_length =50)
votes = models.IntegerField(default=0)
voted_by = ?
Votes is the total number of votes given by users and single user can vote multiple times. If the user have voted then the user should wait 1 hour to vote again. Now i am wondering, how can i store users id in a way that it would be easier to know who voted how many times and the recent date and time the user have voted.
Can someone suggest me or refer some examples that i can solve this problem.
You can create another model (eg. VotesHistory)...
class VotesHistory(models.Model):
class Meta:
verbose_name = "Vote Log"
verbose_name_plural = "Vote Logs"
time = models.DateTimeField(auto_now=True, verbose_name="Time")
uid = models.IntegerField(verbose_name="Voter's UserID")
pid = models.IntegerField(verbose_name="Voted UserID")
Now, when user 1 will vote user 2, you can create an entry such as,
VotesHistory(uid=user1.id, pid=user2.id).save()
This kind of problem is generally solved by using a ForeignKey reference.
# class name should begin with a capital letter and should be singular for a model
class Participant(models.Model):
username = models.CharField(max_length =50)
class Vote(models.Model)
vote_to = models.ForeignKey(Participant, on_delete=models.CASCADE, related_name='vote_to')
voted_by = models.ForeignKey(Participant, on_delete=models.CASCADE, related_name='voted_by')
date_time = models.DateTimeField(auto_now=True)
Each vote by a participant would be a row in the Votes table or an object of type Vote.
Something like,
vote = Vote(vote_to=some_participant_object,
voted_by=someother_participant_object)
vote.save()
auto_now=True means the value will be added when the object gets created so you don't have to handle when the vote was cast.
You can then query the number of votes cast by a particular participant using the ORM.
A basic filter query should be enough. Get all the votes by a particular participant.
Something like,
# just as an idea here, the next lines might not be perfect
votes = Vote.objects.filter(voted_by__id=some_participant_id)
# or
votes = Vote.objects.filter(voted_by=some_participant_object)
# check the timestamp of the last vote and build logic accordingly
This way it'll be easier to write ORM queries to count the number of votes a particular participant has or the number of votes a particular participant has cast.

Django chain multiple queries in view

I have three models:
Course
Assignment
Term
A course has a ManyToManyField which accesses Django's default User in a field called student, and a ForeignKey with term
An assignment has a ForeignKey with course
Here's the related models:
class Assignment(models.Model):
title = models.CharField(max_length=128, unique=True)
points = models.IntegerField(default=0, blank=True)
description = models.TextField(blank=True)
date_due = models.DateField(blank=True)
time_due = models.TimeField(blank=True)
course = models.ForeignKey(Course)
class Course(models.Model):
subject = models.CharField(max_length=3)
number = models.CharField(max_length=3)
section = models.CharField(max_length=3)
professor = models.ForeignKey("auth.User", limit_choices_to={'groups__name': "Faculty"}, related_name="faculty_profile")
term = models.ForeignKey(Term)
students = models.ManyToManyField("auth.User", limit_choices_to={'groups__name': "Student"}, related_name="student_profile")
When a user logs in to the page, I would like to show them something like this bootstrap collapse card where I can display each term and the corresponding classes with which the student is enrolled.
I am able to access all of the courses in which the student is enrolled, I'm just having difficulty with figuring out the query to select the terms. I've tried using 'select_related' with no luck although I may be using it incorrectly. So far I've got course_list = Course.objects.filter(students = request.user).select_related('term'). Is there a way to acquire all of the terms and their corresponding courses so that I can display them in the way I'd like? If not, should I be modeling my database in a different way?
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#values
You could use values or values_list here to get the fields of the related model Term.
For example expanding on your current request:
To retrieve all the Terms' name and duration for the Courses in your queryset
Course.objects.filter(students = request.user).values('term__name', 'term__duration')
I am not sure what the fields are of your Term model, but you would replace name or duration with whichever you are trying to get at.
I think it helps you
terms = Terms.objects.filter(....) # terms
cources0 = terms[0].course_set.all() # courses for terms[0]
cources0 = terms[0].course_set.filter(students=request.user) # courses for terms[0] for user

Django models - Able to dynamically calculate the value of a field

Say for example I have a rating which is attached to a product model like so..
class Product(models.Model):
...
rating = models.IntegerField(...)
I want the product rating to change as new Reviews (that include a star rating of the product) change or updated/deleted.
class Review(models.Model):
...
related_product = models.ForeignKey(Product, on_delete=models.CASCADE, ...)
rating = models.IntegerField(...)
Initially, I used a method on the product class to calculate the value of rating by counting the rating value from each review and then dividing by the number of reviews to get an average.
class Product(models.Model):
...
def rating(self):
total_rating = ...
reviews_count = ...
average = total_rating / reviews_count
However, this doesn't allow me to use order_by('rating') when querying the objects and sending back the objects by order of their rating since 'rating' has to be defined in the database (i.e. as a field instead of a method).
Is there any way that I can calculate the value for rating which is then stored in the database?
You can annotate your queryset to calculate the average using your database
from django.db.models import Avg
Product.objects.all().annotate(
rating=Avg('review_set__rating')
).order_by('rating')
Now each Product object in the queryset will have an additional attribute rating
If you must store this rating because it becomes expensive to calculate then #niklas' comment is the correct solution

Categories