I've build a blog using Django (very minimal functional blog) and I want to be able to show to the user in my blog only the posts he hasn't read yet.
I have 10,000+ posts and I want to show the user every time he log in a random posts he has not seen yet/
I am new with Django and I not sure I should do it the right way.
I have the Post model:
class Post(models.Model):
author = models.ForeignKey('auth.User',on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def approve_comments(self):
return self.comments.filter(approved_comment=True)
def get_absolute_url(self):
return reverse("post_detail",kwargs={'pk':self.pk})
def __str__(self):
return self.title
Thank you!
You should use ManyToManyField:
class Post(models.Model):
author = models.ForeignKey('auth.User',on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
read_users = models.ManyToManyField(User) # Add this line
def publish(self):
self.published_date = timezone.now()
self.save()
def approve_comments(self):
return self.comments.filter(approved_comment=True)
def get_absolute_url(self):
return reverse("post_detail",kwargs={'pk':self.pk})
def __str__(self):
return self.title
You have to keep record of user and which posts he has read. Just like this
class UserReadPost(models.Model):
user = models.ForeignKey(User, releated_name='user_read_posts')
post = models.ForeignKey(Post, releated_name='posts_read_by_users')
read_at = models.DateTimeField(auto_now=True)
You will have to add a record in this table every time a user read some post. You can get all posts which user have not read yet like this.
from django.db.models import OuterRef, Subquery, Exists
post_read_status = UserReadPost.objects.filter(post=OuterRef('post'), user=current_user_object)
Post.objects.all().annotate(has_read=Exists(post_read_status)).exclude(has_read=True).order_by('?')
This can be done using ManyToManyField but adding your own table will give you ability to check when that user read that specific post.
Related
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)
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
Hi I had this error while try to running server. It may cause by the datetime field. Can someone check it for me.
models.py
class Post(models.Model):
author = models.ForeignKey("auth.User", on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
create_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def get_absolute_url(self):
return reverse("post_detail", kwargs={"pk": self.pk})
def publish(self):
self.published_date = timezone.now
self.save()
def approve_comments(self):
return self.comments.filter(approve_comment=True)
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey('mblog.Post', related_name='comments', on_delete=models.CASCADE)
author = models.CharField(max_length=100)
text = models.TextField()
create_date = models.DateTimeField(default=timezone.now)
approve_comment = models.BooleanField(default=False)
def approve(self):
self.approve_comment = True
self.save()
def get_absolute_url(self):
return reverse("post_detail", kwargs={"pk": self.pk})
def __str__(self):
return self.text
views.py
class PostListView(ListView):
model = models.Post
def get_queryset(self):
return models.Post.objects.filter(published_date__lte=timezone).order_by('-published_date')
class DraftListView(LoginRequiredMixin,ListView):
login_url = '/login/'
redirect_field_name = 'mblog/post_list.html'
model = models.Post
def get_queryset(self):
return models.Post.objects.filter(published_date__isnull=True).order_by('created_date')
And had anyway better to set default for the DateTimeField?
Thanks for your time.
I guess you also go through the udemy course, got the same error myself.
Probably not relevant to you anymore, but if someone else had the same problem, it's just a case of adding parenthesis () after timezone.now in Post class in publish method
so it looks like this:
def publish(self):
self.published_date = timezone.now()
self.save()
How to save the current User in models while posting?
class Post(models.Model):
author = models.ForeignKey('auth.User') #Please tell me how to save the current user here
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def approve_comments(self):
return self.comments.filter(approved_comment=True)
def get_absolute_url(self):
return reverse("post_detail", kwargs={'pk': self.pk})
def __str__(self):
return self.title
You view in your view.py file have access to user in request object
def save_post(request):
# you have to fill all needed fields. It's just an example
Post.objects.create(author=request.user)
return HttpResponse()
I have a problem with creating a modelfield which Count number of people who like an article.
I have class Like:
class Reaction(models.Model):
user = models.ForeignKey(User)
article = models.IntegerField(null=True, blank=True)
date = models.DateTimeField(auto_now_add=True, null=True)
and class Article:
from api.reactions.models import Reaction
class Article(models.Model):
user = models.ForeignKey(User)
post = models.TextField()
likes = models.IntegerField(default=0)
def __str__(self):
return self.post
def calculate_likes(self):
likes = Reaction.objects.count(article=self.pk)
self.likes = likes
self.save()
return self.likes
But likes wont be counted.
What's wrong with this? Please help me. Thanks!
def get_likes(self):
return self.likes.all().count()
this should basically be it, you don't need to point a model to an instance of itself, creating a reaction class is overkill.
But if you are still going for it instead of:
likes = Reaction.objects.count(article=self.pk)
Try:
likes = Reaction.objects.filter(article=self.pk).count()