django get an unexpected keyword argument 'slug' - django

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})

Related

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

how can i order items based on a method

i wanna know how can i order a listView using a method , like here i wanna order my posts based on numbers of likes , i am using class based views ... here is my code
models.py
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
# content = models.TextField()
content = RichTextField(blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
post_image = models.ImageField(upload_to='post/cover')
category = models.CharField(choices=LABEL_CHOICES, max_length=1)
slug = models.SlugField()
likes = models.ManyToManyField(User, related_name='blogpost_like')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("core:detail", kwargs={
'slug': self.slug
})
def delete(self, *args, **kwargs):
self.post_image.delete()
super().delete(*args, **kwargs)
#property
def comment_numbers(self):
return Comment.objects.filter(post=self).count()
def number_of_likes(self):
return self.likes.count()
views.py
class PostListView(ListView):
model = Post
template_name = 'home.html'
context_object_name = 'posts'
paginate_by = 6
ordering = ['-date_created']
You cannot use a function to do that but you can write a query to do it. You would need to override get_queryset first of all then use the aggregation function Count:
from django.db.models import Count
class PostListView(ListView):
model = Post
template_name = 'home.html'
context_object_name = 'posts'
paginate_by = 6
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.annotate(
number_of_likes=Count('likes')
).order_by('number_of_likes')
return queryset

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

Get post id in a Class based view

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

Django Views. How can I change this code from functions based to class based

I'm new to django and was doing most of the staff using function based views. Right now I need to change part of my code to class based and I've stacked for 2 days because can't find any information about implementation of categories using classes
So my current code in views.py:
from django.shortcuts import render, get_object_or_404
from .models import Category, Product
def product_list(request, category_slug=None):
category = None
categories = Category.objects.all()
products = Product.objects.filter(available=True)
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
products = Product.objects.filter(category=category)
context = {
'category': category,
'categories': categories,
'products': products
}
return render(request, 'shop/product/list.html', context)
Here is my part of models related to categories:
class Category(models.Model):
title = models.CharField(max_length=150, db_index=True)
slug = models.SlugField(blank=True, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('title',)
verbose_name = 'категория'
verbose_name_plural = 'категории'
def __str__(self):
return self.title
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)
title = models.CharField(max_length=120)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField(null=True)
price = models.DecimalField(max_digits=20, decimal_places=2, default=49.99)
image = models.ImageField(upload_to=upload_image_path, null=True, blank=True)
featured = models.BooleanField(default=False)
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True)
How can I change my views to class based?
P.S I need to combine it with next ListView
class ProductListView(ListView):
template_name = 'products/list.html'
paginate_by = 6
def get_queryset(self, *args, **kwargs):
request = self.request
return Product.objects.all()
def get_context_data(self, *args, **kwargs):
context = super(ProductListView, self).get_context_data(*args, **kwargs)
cart_object, new_object = Cart.objects.new_or_get(self.request)
context['cart'] = cart_object
return context
I couldn't find a way to make it using classes but solved actual problem with next code:
def product_list(request, category_slug=None):
category = None
categories = Category.objects.all()
products = Product.objects.all()
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
products = Product.objects.filter(category=category)
cart_object, new_object = Cart.objects.new_or_get(request)
context = {
'category': category,
'categories': categories,
'products': products,
'cart': cart_object
}
return render(request, 'products/list.html', context)
just added 2 necessary lines from listview to this:
cart_object, new_object = Cart.objects.new_or_get(request)
context = {
'category': category,
'categories': categories,
'products': products,
'cart': cart_object
}
you can change your code like this :
from django.views import View
class ProductListView(View):
def get(self, request, category_slug=None):
category = None
categories = Category.objects.all()
products = Product.objects.filter(available=True)
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
products = Product.objects.filter(category=category)
context = {
'category': category,
'categories': categories,
'products': products
}
return render(request, 'shop/product/list.html', context)
in urls.py, you must do like this :
urlpatterns = [
path('productlist/', ProductListView.as_view()),
]