I am trying to display the post and all the comments of this post. Comments have likes, so their number also needs to be displayed. But it is not possible to optimize these queries.
The problem is that django turns to vi every time to get author and quotes_comment_like from there to count the number of authors who have put likes.
Models.py
class QuotesHonors(models.Model):
quotes = models.TextField()
liked = models.ManyToManyField(Profile,
related_name='likes_quotes', blank=True)
editor = models.ForeignKey(Profile, on_delete=models.DO_NOTHING,
related_name='quotes_editor')
author = models.ForeignKey(Profile, on_delete=models.DO_NOTHING,
related_name='quotes_author')
category = models.ManyToManyField(
'Category', related_name='quotes_category')
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def number_comments(self):
return self.quotes_comment.all().count()
class Like(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE,
related_name='user_like')
quotes = models.ForeignKey(QuotesHonors, on_delete=models.CASCADE,
related_name='quotes_like')
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self) -> str:
return f'"{self.user}" like "{self.quotes}"'
class Comment(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE,
related_name='user_comment')
quotes = models.ForeignKey(QuotesHonors, on_delete=models.CASCADE,
related_name='quotes_comment')
body = models.TextField(max_length=300)
liked = models.ManyToManyField(Profile,
related_name='likes_comment', blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def number_likes(self):
return self.liked.all().count()
def __str__(self) -> str:
return f'"{self.user}" comment "{self.quotes}"'
class CommentLike(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE,
related_name='user_comment_like')
comment = models.ForeignKey(Comment, on_delete=models.CASCADE,
related_name='comment_like')
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self) -> str:
return f'"{self.user}" like comment "{self.comment}"'
Views.py
class QuotesDetail(DetailView):
model = QuotesHonors
template_name = 'quotes/quotes_detail.html'
def get(self, request, *args, **kwargs):
kp = self.kwargs.get('pk')
quote = QuotesHonors.objects.prefetch_related(
Prefetch(
'quotes_comment',
queryset=Comment.objects.select_related('user'))
).get(pk=kp)
user = Profile.objects.get(user=request.user)
context = {
'quote': quote,
'user': user
}
return render(request, self.template_name, context)
Related
I tried to search for answers, but after a few days, I'm here asking:
I'm a beginner, making a todo list app - expanding on a tutorial I followed. Currently, it's filtering by user, which is fine, but I also want to filter by a field in the DB (list).
Models:
class ToDoList(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200)
description = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ['created']
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
list = models.ForeignKey(ToDoList, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Meta:
ordering = ['complete']
View I'm trying to change:
class TaskList(LoginRequiredMixin, ListView):
model = Task
context_object_name = "tasks"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tasks'] = context['tasks'].filter(user=self.request.user)
context['count'] = context['tasks'].filter(complete=False).count
search_input = self.request.GET.get('search-area') or ''
if search_input:
context['tasks'] = context['tasks'].filter(title__startswith=search_input)
context['search_input'] = search_input
return context
Also, is there a way to access the list variable in the html component, like here?
url:
path('tasks/<list>/create', TaskCreate.as_view(), name="task-create"),
html:
← Back
I would like to list out the comments on my Post Detail page and wanted to see how I can connect a view to the specific comments for a given post?
Models.py
class Post(models.Model):
owner = models.ForeignKey(
Profile, null=True, blank=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=200)
body = models.TextField()
Post_image = models.ImageField(
null=True, blank=True, default='default.jpeg')
create_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post', kwargs={'pk': self.pk})
class Meta:
ordering = ['-create_date']
class Comment(models.Model):
owner = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
text = models.TextField()
create_date = models.DateTimeField(auto_now_add=True)
Views.py
class PostDetailView(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comment_list'] = Post.comment_set.all()
return context
You can access the detail object of the DetailView with self.object:
class PostDetailView(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comment_list'] = self.object.comment_set.order_by('create_date')
return context
I want to calculate most popular post by each category, but i have this error DISTINCT ON fields is not supported by this database backend.
after i use PostgreSql, but I also had a error. annotation and distinct together did not work.
model -->
class Category(models.Model):
title = models.CharField(max_length=150, verbose_name=_("კატეგორია"))
def __str__(self):
return self.title
class Question(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name=_("მომხმარებელი")
)
category = models.ManyToManyField(Category)
title = models.CharField(max_length=150, verbose_name=_("სათაური"))
body = models.TextField(verbose_name=_("ტექსტი"))
image = models.ImageField(blank=True, null=True, verbose_name=_("ფოტო"))
link = models.URLField(
max_length=400,
blank=True,
null=True,
validators=[RequireHttpOrHttpsUrl()],
verbose_name=_("ლინკი"),
)
time = models.DateTimeField(auto_now=True)
send_notification = models.BooleanField(
default=True, verbose_name=_("გავაგზავნოთ შეტყობინება?")
)
def __str__(self):
return self.title
class LikeDislike(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name=_("მომხმარებელი")
)
question = models.ForeignKey(
Question, on_delete=models.CASCADE, verbose_name=_("კითხვა")
)
point = models.BooleanField()
time = models.DateTimeField()
def __str__(self):
return self.question.title
view ->
class CountLikeByCategory(generics.ListCreateAPIView):
serializer_class = CountLikeByCategorySerializer
def get_queryset(self):
query=Question.objects.values_list(
'category__title','title'
).annotate(
l=Count('likedislike',filter=Q(likedislike__point=1)),
d=Count('likedislike',filter=Q(likedislike__point=0)),
total=F('l')+F('d'),
).order_by('category', '-total').distinct('category')
return query
who can help me?
i wan correct query
try this:
def get_queryset(self):
query=Question.objects.values_list(
'category','category__title','title'
).annotate(
l=Count('likedislike',filter=Q(likedislike__point=1)),
d=Count('likedislike',filter=Q(likedislike__point=0)),
total=F('l')+F('d'),
).order_by('category', '-total').distinct('category')
return query
I am new to django and am creating a question answer app
I am getting the following error:
The QuerySet value for an exact lookup must be limited to one result using slicing.
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.utils.text import slugify
from django.contrib.auth.models import User
class Log(models.Model):
title = models.CharField(blank=False, max_length=500)
content = models.TextField(blank=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=50, null=False)
created_by = models.CharField(null=True, max_length=500)
avatar = models.ImageField(
upload_to='images', blank=True)
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.title)
super().save(*args, **kwargs)
class Meta:
verbose_name = ("Log")
verbose_name_plural = ("Logs")
def __str__(self):
return f"{self.title}"
class Solutions(models.Model):
log = models.ForeignKey(
Log, on_delete=models.CASCADE, blank=True, null=True)
solution = models.TextField(null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=50, null=False, blank=True)
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.title)
super().save(*args, **kwargs)
class Meta:
verbose_name = ("Solution")
verbose_name_plural = ("Solutions")
def __str__(self):
return f" {self.log.title} {self.solution} "
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
log = models.ForeignKey(Log, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"like by {self.user.username} for {self.log.title}"
class Comments(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
log = models.ForeignKey(
Solutions, on_delete=models.CASCADE, null=True, blank=True)
comment = models.TextField(null=True, blank=True)
created_by = models.CharField(null=True, max_length=500)
class Meta:
verbose_name = ("Comment")
verbose_name_plural = ("Comments")
def __str__(self):
return f"{self.comment}"
The error that I am getting is in getting the comments of a particular solution.
The function for that in views.py:
def solution(request, id, question):
solution = Solutions.objects.filter(id=id)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
solution = Solutions.objects.filter(id=id)
com = form.cleaned_data['comment']
c = Comments()
c.comment = com
c.created_by = request.user.username
c.log = solution
print(c)
c.save()
message = messages.add_message(request, 25,
'Comment added successfully')
return HttpResponseRedirect(f'/solution/{id}/{solution.slug}')
else:
message = messages.add_message(request, 30,
'Error')
else:
form = CommentForm()
message = ''
try:
solution = Solutions.objects.filter(id=id)
print(solution)
comment = Comments.objects.filter(log=solution)
except Solutions.DoesNotExist:
comment = ''
solution = ''
context = {
'comments': comment,
'forms': form,
'message': message,
'solution': solution,
}
return render(request, 'solution.html', context=context)
The error is in the line solution = Solutions.objects.filter(id=id)
When I print the solution, it gives me a an empty query set.. Can anyone tell me the right way to do it?
I have a question (log as per in database) and solution to that question.. And the solutions have comments
Thanks
solution = Solutions.objects.get(id=id)
filter returns a QuerySet while get returns an object.
Solution.objects.filter(id=id) returns a QuerySet and it could be emplty if the Solution with such id does not exist. In this case you cannot get an exception you want. Use Solution.objects.get(id=id), then you will get a single instance or the Solutions.DoesNotExist exception.
BTW, id is a bad naming for variable in python, because id is a standard python function.
Please I need help, I dont know where the problem is coming from, please see the code below
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def post_feed_view(request, *args, **kwargs):
user = request.user
profiles = user.follow_user.all()
followed_users_id = []
if profiles.exists():
followed_users_id = [x.user.id for x in profiles]
followed_users_id.append(user.id)
queryset = Post.objects.filter(user__id__in=followed_users_id).order_by("-date_posted")
serializer = PostSerializer(queryset, many=True)
return Response(serializer.data, status=200)
I keep getting this error: Cannot resolve keyword 'user' into field. Choices are: author, author_id,
although, in my models, I dont have "User" what I have is "Author".
But I dont know where exactly to put in author. I think my problem is that i dont fully understand "request.user".
Please help!.
===========
This is the Profile and Follow models:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(max_length=245, null=True)
image = models.ImageField(default='default.png', upload_to='profile_pics')
interests = models.ManyToManyField(Category, related_name='interests_user')
stripe_customer_id = models.CharField(max_length=50, blank=True, null=True)
one_click_purchasing = models.BooleanField(default=False)
is_vendor = models.BooleanField(default=False)
# vendor
bvn = models.CharField(max_length=10, null=True, blank=True)
description = models.TextField(null=True, blank=True)
address = models.CharField(max_length=200, null=True, blank=True)
company = models.CharField(max_length=100, null=True, blank=True)
# follow_user = models.ManyToManyField('users.Follow')
def __str__(self):
return f'{self.user.username} Profile'
#property
def followers(self):
return Follow.objects.filter(follow_user=self.user).count()
#property
def following(self):
return Follow.objects.filter(user=self.user).count()
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
super().save()
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
class Follow(models.Model):
user = models.ForeignKey(User, related_name='user', on_delete=models.CASCADE)
follow_user = models.ForeignKey(User, related_name='follow_user', on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
old_instance = models.ForeignKey('Follow', blank=True, null=True, on_delete=models.CASCADE, editable=False)
def save(self, *args, **kwargs):
if self.pk is not None:
self.old_instance = Follow.objects.get(pk=self.pk)
super().save(*args,**kwargs)
def __str__(self):
return f"For: {self.user} // id: {self.id}"
class FollowerRelation(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile = models.ForeignKey("Profile", on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
Your Post model apparently has no user field, but an author field, so you can filter with:
queryset = Post.objects.filter(
author_id__in=followed_users_id
).order_by('-date_posted')
But that being said, you should not filter like that. Given your models you can do this in a single query and thus avoiding the N+1 problem. You can simply filter with:
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def post_feed_view(request, *args, **kwargs):
queryset = Post.objects.filter(
author__follow_user__user=request.user
).order_by('-date_posted')
serializer = PostSerializer(queryset, many=True)
return Response(serializer.data, status=200)