Reputation: 17
I need that read_books
field (in Purchased), return the Rating
objects count.
Should return the number of objects according to the filter of the same collections of each book in Rating
and the same user.
I don't know how to do this because Rating
and Purchased
are not directly dependent.
rating/models.py
class Rating(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
book = models.ForeignKey(Book, on_delete=models.CASCADE, null=False)
rating = models.IntergerField(default=0)
book/models.py
class Books(models.Model):
collection = models.ForeignKey(Collection, on_delete=models.DO_NOTHING, blank=True, null=True)
book = models.CharField(max_length=250, blank=True, null=True)
collection/models.py
class Collection(models.Model):
title = models.CharField(max_length=50)
creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
purchased_collections/models.py
class Purchased(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
collection = models.ForeignKey(Collection, on_delete=models.DO_NOTHING)
date = models.DateTimeField(default=datetime.now)
read_books = models.IntegerField(default=0)
AFTER APPLICATION OF @ruddra 'S RESPONSE
The first option:
def read_books(self):
return Rating.objects.filter(user=self.user, book__collection=self.collection).count()
worked in models.py
. But I wanted to run this function only when the user logs in.
So I tried to put it in def login (request):
in views.py,
but, it is not based on a class
, I can't use the (self). Always returns the error name 'self' is not defined.
So, I tried the secont @ruddra 's suggestion:
purchases = Purchased.objects.annotate(read_books=Count('collection__books__rating', filter=Q(collection__books__rating__user=F('user'))))
for item in purchases:
print(item.read_books)
views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from .login import login_user
from purchased.models import Purchased
from rating.models import Rating
from collection.models import Collection
from book.models import Books
from django.db.models import F, Count, Q
def login(request):
if not request.user.is_authenticated:
if request.method == 'POST':
login_status = login_user(request)
if login_status != 1:
messages.error(request, 'Invalid')
return redirect('login')
else:
messages.success(request, 'You are now logged in')
purchases = Purchased.objects.annotate(read_books=Count('collection__books__rating', filter=Q(collection__books__rating__user=F('user'))))
for item in purchases:
print(item.read_books)
return redirect('home')
else:
return render(request, 'users/login.html')
else:
messages.error(request, 'You are already logged in')
return redirect('index')
but ever return error: NameError: name 'collection__books__rating__user' is not defined.
The problem is to be able to filter each ratings
objects by their own collection
. Using (self) in models.py
it works perfectly, but I can't make it work without (self).
Any other suggestions to make this count run only when the user logs in?
Upvotes: 0
Views: 76
Reputation: 51948
Assuming you meant book = models.ForeignKey(Book, on_delete=models.CASCADE, null=False)
in Rating
model:
You can use a property method to return the count:
class Purchased(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
collection = models.ForeignKey(Collection, on_delete=models.DO_NOTHING)
date = models.DateTimeField(default=datetime.now)
@property
def read_books(self):
return Rating.objects.filter(user=self.user, book__collection=self.collection).count()
Or better, if you use annotation
(which will reduce DB hits and you can use that for querying):
from django.db.models import Count, F, Q
purchases = Purchased.objects.annotate(read_books=Count('collection__books__rating', filter=Q(collection__books__rating__user=F('user'))))
for item in purchases:
print(item.read_books)
Upvotes: 1
Reputation: 3920
As mentioned in the comments, if you are using Book
as the foreign key related model, then you can find out the count by:
class Purchased(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
collection = models.ForeignKey(Collection, on_delete=models.DO_NOTHING)
date = models.DateTimeField(default=datetime.now)
read_books = models.IntegerField(default=0)
def save(self):
self.read_books = Rating.objects.filter(user=self.user, book__in=self.collection.books_set).count()
return super().save()
Upvotes: 1