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)
Related
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'))
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'
)
I work on cinema booking app. I've already created table in frontend, contains 100 seats (10 rows x 10 seats). Each seat is "td". I thought about making each td an object of the model so I can easily assign users later on. Basing on main model's max_seats i want to create the objects. After adding a new movie to db the objects should get created automatically. Any idea or hint where to start ?
My main model:
class Movies(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
max_seats = models.IntegerField(default=100)
And the model where i need to create the objects:
class Seat(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
movie = models.ForeignKey(Movies, on_delete=models.CASCADE)
row = models.CharField(max_length=1)
number = models.IntegerField()
You can do that with your current ForeignKey and create seats in views.py or anywhere else in your code. You can also access list of seats using getSeatsList function below:
Your movie model:
class Movies(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
max_seats = models.IntegerField(default=100)
def __init__(self, *args, **kwargs):
super(Movies, self).__init__(*args, **kwargs)
# Change Movies field if necessary here
for i in range(self.max_seats):
new_seat = Seat()
new_seat.customer = None
new_seat.movie = self
new_seat.row = i%10 + 1
new_seat.number = i + 1
new_seat.save()
def getSeatsList(self):
return list(self.movie_seats.all())
And your seat model:
class Seat(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE, default=None, null=True, blank=True)
# Adding a Foreign Key with a related name
movie = models.ForeignKey(Movies, on_delete=models.CASCADE, related_name='movie_seats', null=True, blank=True)
row = models.CharField(max_length=1)
number = models.IntegerField()
Or alternatively, in your views.py or anywhere else when you create a new Movie, you can create a list of seats and assign them to your movie:
new_movie = Movies()
new_movie.title = "New Title"
new_movie.price = 20
new_movie.max_seats = 100
new_movie.save()
for i in range(new_movie.max_seats):
new_seat = Seat()
new_seat.customer = None
new_seat.movie = new_movie
new_seat.row = i%10 + 1
new_seat.number = i + 1
new_seat.save()
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.