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()
query to fetch top rated movie with minimum 5 people rated.
You should read basics about django's annotation.
In your case, something like this should work:
from django.db.models import Count, Sum, F
qs = Movie.objects.annotate(vote_count=Count('watchlist_set'),
vote_sum=Sum('watchlist_set__rating'),
rating = F('vote_sum')/F('vote_count')
).filter(
vote_count__gte=5,
).order_by(
'-rating'
)
Related
I have here 2 django database table
class ProductName(models.Model):
name = models.CharField(max_length=100)
class Inventory(models.Model):
product = models.ForeignKey(ProductName, on_delete = models.CASCADE )
qty = models.PositiveIntegerField()
class Sold(models.Model):
product = models.ForeignKey(ProductName, on_delete = models.CASCADE )
qty = models.PositiveIntegerField()
I would like to have an inventory table page wherein I can see the total qty left in Inventory (for example: Inventory.qty - Sold.qty) .
how to do this in Django ?
In your views file
from .model import Inventory, Sold
qty_left = Inventory.objects.count() - Sold.objects.count()
I need to find maximum score of user id with the maximum quiz score in a category.
My Model:
class QuizCat(models.Model):
cid = models.IntegerField(unique=True)
c_name = models.CharField(max_length=200)
class Quiz(models.Model):
Qid = models.IntegerField()
cat_id = models.ForeignKey(QuizCat, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
class UserDetails(models.Model):
user_id = models.IntegerField()
Qid = models.ForeignKey(Quiz, on_delete=models.CASCADE)
score = models.IntegerField()
I tried:
category_id = request.GET.get('category_id')
result = UserDetails.objects.all().values('user_id').annotate(score=Sum('score')).filter(Qid__cat_id=category_id)
But the above did not work.
Instead of Sum, use Max:
result = UserDetails.objects.filter(Qid__cat_id=category_id).values('user_id').annotate(score=Max('score'))
I have 2 models
class Movie(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
vote_count = models.IntegerField()
def __str__(self):
return self.title
class Watchlist(models.Model):
userid = models.IntegerField()
movie_id = models.ForeignKey(Movie, on_delete=models.CASCADE)
rating = models.IntegerField()
def __int__(self):
return self.userid
what will be query to fetch highest watched movie
from django.db.models import Count
# the most watched Movie instance
the_most_watched_movie = Movie.objects.annotate(count=Count('watchlist')).order_by('-count').first()
Also it could be done via Watchlist if you would need it for some reason
watchlist = Watchlist.objects.annotate(count=Count('userid')).values('movie_id', 'count').order_by('-count').first()
movie_id = watchlist['movie_id'] # the most watched movie id
# the most watched Movie instance
the_most_watched_movie = Movie.objects.get(id=movie_id)
class Album(models.Model):
title = models.CharField(max_length=100, blank=True, default='')
price = models.FloatField()
upload_time = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('upload_time',)
class Status(models.Model):
user_id = models.IntegerField()
album_id = models.IntegerField()
favorite = models.BooleanField(default=False)
purchase = models.BooleanField(default=False)
history = models.BooleanField(default=False)
def __str__(self):
return self.user_id
in a ModelViewSet I wrote like this:
class index(viewsets.ModelViewSet):
serializer_class = AlbumSerializer
queryset = Album.objects.all()
As the image shown above, I need output the count of purchases of each Album, e.g. Album 1 has been purchased 4 times, Album 3 has been purchased 1 time.
But right now, my index view only generate the fields in Album data model.
What should I do to implement this, add the purchase number for each Album? Need your help...
You can add something like this to your serializer class to count it:
class AlbumSerializer(serializers.ModelSerializer):
purchase_count = serializers.SerializerMethodField(read_only=True)
def get_purchase_count(self, obj):
return Status.objects.filter(album_id=obj.id, purchase=True).count()
Connect your Album and User models as many to many relation:
class Status(models.Model):
user = models.ForeignKey('userapp.User', on_delete=models.CASCADE)
album = models.ForeignKey('albumapp.Album', on_delete=models.CASCADE)
favorite = models.BooleanField(default=False)
purchase = models.BooleanField(default=False)
history = models.BooleanField(default=False)
Don't forget to apply migrations.
Do query with annotation:
queryset = Album.objects.all().annotate(
purchase_count=Count('status', filter=Q(status__purchase=True)),
favorite_count=Count('status', filter=Q(status__favorite=True)),
history_count=Count('status', filter=Q(status__history=True)),
)
In attributes purchase_count, favorite_count and history_count you'll have corresponding values.
Consider the following database model:
class User:
id = models.BigAutoField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Restaurant:
id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=50)
class Rating:
id = models.BigAutoField(primary_key=True)
by_user = models.ForeignKey(to='User',
on_delete=models.PROTECT,
related_name='written_ratings')
for_restaurant = models.ForeignKey(to='Restaurant',
on_delete=models.PROTECT,
related_name='received_ratings')
score = models.SmallIntegerField()
# make sure only one vote per user per restaurant
class Meta:
unique_together = ('by_user', 'for_restaurant')
For a given User, we can obtain a list of Restaurant that we have not yet rated by performing the following query (that I have learned from my last post)
eligible_restaurants = Restaurant.objects.exclude(rating__by_user_id=my_id)
But what happens when the Ratings don't point directly at the Restaurants - but rather at an intermediate Profile object?
class User:
id = models.BigAutoField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Restaurant:
id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=50)
current_profile = models.OneToOneField(to='Profile',
on_delete=models.PROTECT,
related_name='+')
# the `+` means to not generate a related name
class Profile:
# this is here acting as an intermediate between
# `Restaurant` and `Rating` so that we can keep track
# of all reviews - deleting/remaking would simply be
# creating a new `Profile` and setting the `Restaurant`
# to point to it instead - the old one will act as a
# historical record
id = models.BigAutoField(primary_key=True)
by_restaurant = models.ForeignKey(to='Restaurant',
on_delete=models.PROTECT,
related_name='written_profiles')
picture_url = models.CharField(max_length=500)
picture_desc = models.CharField(max_length=500)
class Rating:
id = models.BigAutoField(primary_key=True)
by_user = models.ForeignKey(to='User',
on_delete=models.PROTECT,
related_name='written_ratings')
for_profile = models.ForeignKey(to='Profile',
on_delete=models.PROTECT,
related_name='received_ratings')
score = models.SmallIntegerField()
# make sure only one vote per user per restaurant
class Meta:
unique_together = ('by_user', 'for_profile')
How would I query for eligible restaurants now?
You could filter them starting with restaurants
restaurant_ids = Rating.objects.filter(by_user=user).values_list('for_profile__by_restaurant', flat=True).distinct()
eligible_restaurants = Restaurant.objects.exclude(id__in=restaurant_ids)
Note: this will generate only one query because django's querysets are lazy.