Get post id in a Class based view - django

Trying to get post id in Detailview in views.py .I am trying to add like button on blog Detail page.
I think I need to add id in kwargs in get_absolute_url function but that didn't work or I didn't add that correctly.so, please help me.
#views.py
class PostDetail(DetailView):
model = Post
template_name = 'post_detail.html'
def get_context_data(self, *args, **kwargs):
context = super(PostDetail, self).get_context_data(*args, **kwargs)
post = get_object_or_404(Post, id=self.kwargs['id'])
is_liked = False
if post.likes.filter(id=request.user.id).exists():
is_liked = True
context["post"] = post
context["is_liked"] = is_liked
return context
model.py
class Post(models.Model):
cover = models.URLField(blank=True)
tag = models.CharField(max_length=100, unique=True, default=0)
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(accountUser, on_delete=models.CASCADE)
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
likes = models.ManyToManyField(accountUser, related_name='likes', blank=True)
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ["-created_on"]
def __str__(self):
return self.title
def total_likes(self):
return self.likes.count()
def get_absolute_url(self):
return reverse("post_detail", kwargs={"slug": str(self.slug)})
Error in terminal
#error
post = get_object_or_404(Post, id=self.kwargs['id'])
KeyError: 'id'

self.kwargs is different in get_context_data kwargs, and kwargs depend of your url
replace:
post = get_object_or_404(Post, id=self.kwargs['id'])
by :
post = self.get_object()
you are in DetailView, so you have methods get_object, for getting yout post object with verify if object exsits

Related

django get an unexpected keyword argument 'slug'

I get error but I can't understand how to fix it:
(MainPage.get() got an unexpected keyword argument 'slug')
This is my model:
class Book(models.Model):
title = models.CharField(max_length=256)
price = models.IntegerField()
category = models.ForeignKey('Category', on_delete=models.PROTECT)
created_date = models.DateField(auto_now_add=True)
description = models.TextField(blank=True, null=True)
count = models.IntegerField(default=0)
author = models.ForeignKey('Author', on_delete=models.PROTECT)
class Category(models.Model):
name = models.CharField(max_length=256)
slug = models.SlugField(blank=True, unique=True, allow_unicode=True)
created_date = models.DateField(auto_now_add=True)
This is my view:
class MainPage(View):
def get(self, request):
books = models.Book.objects.all()
return render(request, 'core/index.html', {'books': books})
class CategoryPage(View):
def get(self, request):
categories = models.Category.objects.all()
return render(request, 'core/category.html', {'categories': categories})
This is my urls:
urlpatterns = [
path('', views.MainPage.as_view(), name='MainPage'),
path('category/', views.CategoryPage.as_view(), name='Category'),
path('category/<slug:slug>/', views.MainPage.as_view(), name='BookList')]
When you use 'category/<slug:slug>/', django passes slug to your view.
So, either use **kwargs in your view, or declare slug as param in your view:
class MainPage(View):
def get(self, request, *args, **kwargs):
# get slug from kwargs and use it as you want
books = models.Book.objects.all()
return render(request, 'core/index.html', {'books': books})
Or:
class MainPage(View):
def get(self, request, slug):
# Use slug as you want
books = models.Book.objects.all()
return render(request, 'core/index.html', {'books': books})

Django change <a> tag on template depending on a condition

I have posts with the option of saving it. The view works properly but I can't see the change in the button. I want that when it is not saved by a user the button says "Save post" and when it is already saved the button should say "unsave". I'm getting problems with this last part. Here part of the code.
views.py
def post(request):
posts = Post.objects.all().order_by("-date_created")
return render(request, "post/food-feed.html", {"posts": posts})
def save_post(request, pk):
post = get_object_or_404(Post, id=pk)
if post.favorite_posts.filter(id=request.user.id).exists():
post.favorite_posts.remove(request.user)
else:
post.favorite_posts.add(request.user)
return HttpResponseRedirect(request.META["HTTP_REFERER"])
template
Save post
urls.py
path("post/<int:pk>/save", views.save_post, name="save-post")
forms.py
class UserSignupForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]
def clean_username(self):
username = self.cleaned_data["username"].lower()
if not re.match(r"^[A-Za-z0-9_]+$", username):
raise forms.ValidationError(
"Sorry, your username must only contain letters, numbers and underscores."
)
elif (
User.objects.exclude(pk=self.instance.pk).filter(username=username).exists()
):
raise forms.ValidationError(f"Username {username} is already in use.")
else:
return username
models.py
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=80)
slug = models.SlugField(max_length=250, null=True, blank=True)
post_description = models.TextField(max_length=140, null=True, blank=True)
date_created = models.DateTimeField(default=timezone.now)
date_updated = models.DateTimeField(auto_now=True)
main_image = models.ImageField(upload_to="post_pics")
is_recipe = models.BooleanField()
ingredients = models.TextField(blank=True, null=True)
recipe_description = models.TextField(blank=True, null=True)
cooking_time = models.CharField(max_length=20, blank=True, null=True)
likes = models.ManyToManyField(User, related_name="post_likes")
loves = models.ManyToManyField(User, related_name="post_loves")
drooling_faces = models.ManyToManyField(User, related_name="post_drooling_faces")
favorite_posts = models.ManyToManyField(
User, related_name="favorite_posts", default=None, blank=True
)
def clean(self, *args, **kwargs):
if (
(self.is_recipe and self.ingredients == None)
or (self.is_recipe and self.ingredients == None)
or (self.is_recipe and self.recipe_description == None)
or (self.is_recipe and self.cooking_time == None)
):
raise ValidationError("You need to complete the recipe fields!")
if not self.slug:
slug_title = slugify(self.title)
slug_date = slugify(self.date_created)
self.slug = f"{slug_title}-{slug_date}"
super().clean(*args, **kwargs)
class Meta:
ordering = ("-date_created",)
def save(self, *args, **kwargs):
self.full_clean()
return super().save(*args, **kwargs)
def __str__(self) -> str:
return self.title
def get_absolute_url(self):
return reverse("post-detail", kwargs={"slug": self.slug})
def like_count(self):
return self.likes.count()
def love_count(self):
return self.loves.count()
def droolingface_count(self):
return self.drooling_faces.count()
Each post is shown in the feed-food template with user image, user username, date, photo, title, likes, description and THE SAVE BUTTON
What do I need to add to make the statement work?
You can do using queryset anotation or custom filter tag.
I don't know your models. but you can annotate is_favorite something like this in post view:
from django.db.models import Exists, OuterRef
Post.objects.annotate(
is_favorite=Exists(
Favorite.objects.filter(user=user, product_id=OuterRef('pk'))
)
)
in template:
{% if post.is_favorite %}
save
{% else %}
unsave
{% endif %}

Trying to add slug to end of get_absolute_url function in models (Django)

I have a function in my Post model, a get_absolute_url which is a reverse for 'post-detail', it has kwargs for primary key , how do i add another for slug; which is in my Profile model.
At the moment I'm getting error :
NoReverseMatch at /post/26/tested123/update/
Reverse for 'post-detail' with keyword arguments '{'pk': 26}' not found. 1 pattern(s) tried: ['post/(?P[0-9]+)/(?P[-a-zA-Z0-9_]+)/$']
This error occurs when I click the update button on my update post page
feed model
feed/models.py
class Post(models.Model):
description = models.TextField(max_length=255)
pic = models.ImageField(upload_to='path/to/img', blank=True)
date_posted = models.DateTimeField(default=timezone.now)
user_name = models.ForeignKey(User, on_delete=models.CASCADE)
tags = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.description
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
profile model
users/models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png', upload_to='profile_pics')
slug = AutoSlugField(populate_from='user')
bio = models.CharField(max_length=255, blank=True)
friends = models.ManyToManyField('Profile', blank=True)
def __str__(self):
return str(self.user.username)
def get_absolute_url(self):
return "/users/{}".format(self.slug)
views.py
#login_required
def post_detail(request, pk, slug):
post = get_object_or_404(Post, pk=pk)
user = request.user
is_liked = Like.objects.filter(user=user, post=post)
if request.method == 'POST':
form = NewCommentForm(request.POST)
if form.is_valid():
data = form.save(commit=False)
data.post = post
data.username = user
data.save()
return redirect('post-detail', pk=pk, slug=slug)
else:
form = NewCommentForm()
return render(request, 'feed/post_detail.html', {'post':post, 'is_liked':is_liked, 'form':form})
views.py
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Post
fields = ['description', 'pic', 'tags']
template_name = 'feed/create_post.html'
def form_valid(self, form):
form.instance.user_name = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.user_name:
return True
return False
Your get_absolute_url in Post doesn't have slug in kwargs or I'm missing something? 'slug': self.user_name.profile.slug

order by method is not working on queryset

order by not working on queryset no working at all and i dont know where is the mistake seems everything is okay !
views.py
class PostDetailView(DetailView):
model = Post
template_name = 'detail.html'
#context_object_name = 'post'
#form_class = CommentForm
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
post_comments = Comment.objects.filter(post=self.get_object()).order_by('-date_added')
data['comments'] = post_comments
if self.request.user.is_authenticated:
data['comment_form'] = CommentForm(instance=self.request.user)
return data
def post(self, request, slug, *args, **kwargs):
new_comment = Comment(comment=request.POST.get('comment'),
name = self.request.user,
post = self.get_object())
new_comment.save()
return redirect('core:detail', slug=slug)
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
name = models.ForeignKey(User, on_delete=models.CASCADE)
comment = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.comment

User report function

I want to implement a report feature with Django in my blog which users will be able click a link/button under a post and the admin will be notified and he will decide if the post shows up on the homepage or not .
My Post model
class Post(models.Model):
title = models.CharField(max_length=225)
post_image = models.ImageField(null=True, blank=True, upload_to="images/")
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
post_date = models.DateField(auto_now_add=True)
likes = models.ManyToManyField(User, related_name='blog_posts')
def total_likes(self):
return self.likes.count()
def __str__(self):
return self.title + ' | ' + str(self.author)
def get_absolute_url(self):
return reverse('post-detail', args=(str(self.id)),)
My views.py
def LikeView(request, pk):
post = get_object_or_404(Post, id=request.POST.get('post_id'))
liked = False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
liked = False
else:
post.likes.add(request.user)
liked = True
return HttpResponseRedirect(reverse('post-detail', args=[str(pk)]))
class HomeView(ListView):
model = Post
template_name = 'home.html'
ordering = ['-post_date']
class Suggest(ListView):
queryset = Post.objects.annotate(like_count=Count('likes')).order_by('like_count')
template_name = 'home.html'
context_object_name = 'post_list' # Providing a useful context_object_name is always a good idea
class PostDetail(DetailView):
model = Post
template_name = 'post_detail.html'
def get_context_data(self, *args, **kwargs):
context = super(PostDetail, self).get_context_data()
current_post = get_object_or_404(Post, id=self.kwargs['pk'])
total_likes = current_post.total_likes()
liked = False
if current_post.likes.filter(id=self.request.user.id).exists():
liked = True
context['total_likes'] = total_likes
context['liked'] = liked
return context
class AddPost(CreateView):
model = Post
form_class = PostForm
template_name = 'add_post.html'
# fields = '__all__'
success_url = reverse_lazy('home')
Thanks in advance!
...................................................
You should probably at least add another attribute to your Post model that can determine whether or not a particular post should even display on the homepage.
From there, I think you need to decide how admins will actually review these posts/set them to be visible on the homepage. It could be as simple as sending them an email and having them log into the django admin to find the post in question and set this new homepage display attribute as needed.
The email could even include a URL to the post in question directly!
For more information on sending emails from django, check this out:
https://docs.djangoproject.com/en/3.1/topics/email/