how can i order items based on a method - django

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

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

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

AttributeError 'NarrateUpdate' object has no attribute 'object'

I got an attribute error on my NarrateUpdate view. I want to edit/update a user submission from a form
Here's my views.py:
class NarrateUpdate(SuccessMessageMixin, UpdateView):
model = Narrate
fields = ['title', 'body']
template_name = 'narrate_update_form.html'
success_url = reverse_lazy('narrate-status')
success_message = "Narration successfully updated"
def get(self, request, *args, **kwargs):
footer = FooterLinks.objects.all()
context = self.get_context_data(**kwargs)
context['footer'] = footer
return self.render_to_response(context)
The urls.py
path('narration/<int:pk>/update/', NarrateUpdate.as_view(), name='edit-narration'),
And here's the models.py:
class Narrate(models.Model):
STATUS = (
('F', 'FOR REVIEW'),
('P', 'PASSED'),
)
title = models.CharField(max_length=255)
body = models.CharField(max_length=10000)
status = models.CharField(
max_length=25, choices=STATUS, default='for_review', blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return "/narration/%i/" % self.title
class Meta:
verbose_name = "narration"
verbose_name_plural = "narrations"
What can I do to make this work?
Why are you overriding the get method? If you want to add footer better to do it in get_context_data() method:
class NarrateUpdate(SuccessMessageMixin, UpdateView):
model = Narrate
fields = ['title', 'body']
template_name = 'narrate_update_form.html'
success_url = reverse_lazy('narrate-status')
success_message = "Narration successfully updated"
def get_context_data(self, **kwargs):
context = super(NarrateUpdate, self).get_context_data(**kwargs)
context['footer'] = FooterLinks.objects.all()
return context

How to specify a list of values ​in a form in which CheckboxSelectMultiple is used?

I have a problem with the form in django. It uses the CheckboxSelectMultiple widget, but I need to set a list of possible choices only for posts created by the currently logged in user.
Any idea?
form:
class CycleForm(BSModalForm):
class Meta:
model = Cycle
fields = ['title', 'description', 'posts']
widgets = {
'posts': forms.CheckboxSelectMultiple(),
}
models
class Cycle(models.Model):
title = models.CharField(max_length=200, unique=True)
description = models.TextField(max_length=500, default="Brak opisu")
date_created = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
posts = models.ManyToManyField(Post)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=50, unique=True)
content = MDTextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
numbers_of_entries = models.IntegerField(default=0)
views
class CycleCreateView(BSModalCreateView, LoginRequiredMixin):
template_name = 'blog/cycle_form.html'
form_class = CycleForm
def form_valid(self, form, **kwargs):
form.instance.author = self.request.user
return super().form_valid(form)
def get_success_url(self):
reverse_user = self.request.user
return reverse('profile', kwargs={'username': reverse_user})
class CycleUpdateView(BSModalUpdateView):
model = Cycle
template_name = 'blog/cycle_update.html'
form_class = CycleForm
success_message = 'Success: Cycle was updated.'
def get_success_url(self):
reverse_user = self.request.user
return reverse('profile', kwargs={'username': reverse_user})
We can slightly alter the CycleForm form and add a user parameter. If that parameter is set, we filter the queryset of the posts field by only using Posts
class CycleForm(BSModalForm):
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
if user is not None:
self.fields['posts'].queryset = Post.objects.filter(author=user)
class Meta:
model = Cycle
fields = ['title', 'description', 'posts']
widgets = {
'posts': forms.CheckboxSelectMultiple(),
}
Now we only need to pass the user to the form, we can override the get_form_kwargs method [Django-doc]:
class CycleCreateView(LoginRequiredMixin, BSModalCreateView):
template_name = 'blog/cycle_form.html'
form_class = CycleForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update(user=self.request.user)
return kwargs
def form_valid(self, form, **kwargs):
form.instance.author = self.request.user
return super().form_valid(form)
def get_success_url(self):
reverse_user = self.request.user
return reverse('profile', kwargs={'username': reverse_user})
You should do the same with the UpdateView. Note that your LoginRequiredMixin likely should be put first in the base classes.

django class view Overlapping

I am not good at English.
Please understand me.
I'm creating a blog in Django.
I am making it into class view, but I want to see a reple list and form in the post details view.
like this
enter image description here
POST detailview has already been implemented and I don't know how to add comments.
Should I be function view?
Give me some advice.
code
views.py
class BlogLV(LoginRequiredMixin,ListView):
model = Blog
def get_queryset(self):
return Blog.objects.exclude(user=self.request.user)
class BlogCV(LoginRequiredMixin,CreateView): # blog_form.html
model = Blog
fields = ['name','description','image']
success_url = reverse_lazy('blog:index')
def form_valid(self, form): #오류
form.instance.user = self.request.user #user 설정
form.instance.slug = self.request.user
return super(BlogCV,self).form_valid(form)
class BlogDV(LoginRequiredMixin,DetailView):
model = Blog
class PostCreateView(LoginRequiredMixin,CreateView):
model = Post
fields = ['title', 'content']
success_url = reverse_lazy('blog:index')
template_name = 'blog/post_form.html'
def get_context_data(self, **kwargs):
context = super(PostCreateView, self).get_context_data(**kwargs)
context['blog'] = Blog.objects.get(slug=self.kwargs['slug'])
return context
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.slug = self.request.user
return super(PostCreateView, self).form_valid(form)
class PostDV(LoginRequiredMixin,DetailView):
model = Post
fields =['title','content']
def get_context_data(self, **kwargs):
context = super(PostDV, self).get_context_data(**kwargs)
context['blog'] = Blog.objects.get(slug=self.kwargs['slug'])
return context
class PostLV(LoginRequiredMixin,ListView):
model = Post
paginate_by = 5
def get_context_data(self, *, object_list=None, **kwargs):
context = super(PostLV,self).get_context_data(**kwargs)
context['blog'] = Blog.objects.get(slug=self.kwargs['slug'])
return context
def get_queryset(self):
return Post.objects.filter(slug=self.kwargs['slug'])
class PostDeleteView(LoginRequiredMixin,DeleteView):
model = Post
success_url = reverse_lazy('blog:index')
def get_context_data(self, *, object_list=None, **kwargs):
context = super(PostDeleteView,self).get_context_data(**kwargs)
context['blog'] = Blog.objects.get(slug=self.kwargs['slug'])
return context
class PostUV(LoginRequiredMixin,UpdateView):
model = Post
fields = ['title','content']
success_url = reverse_lazy('blog:index')
def get_context_data(self, *, object_list=None, **kwargs):
context = super(PostUV,self).get_context_data(**kwargs)
context['blog'] = Blog.objects.get(slug=self.kwargs['slug'])
return context
urls.py
urlpatterns = [
url(r'^$',BlogLV.as_view(),name="index"),
url(r'^create/$',BlogCV.as_view(),name='blog_create'),
url(r'^(?P<slug>[-\w]+)/$',BlogDV.as_view(),name='blog_detail'),
url(r'^(?P<slug>[-\w]+)/post/create/$',PostCreateView.as_view(),name='post_create'),
url(r'^(?P<slug>[-\w]+)/post/$',PostLV.as_view(),name='post_list'),
url(r'^(?P<slug>[-\w]+)/post/(?P<pk>[0-9]+)/$', PostDV.as_view(), name='post_detail'),
url(r'^(?P<slug>[-\w]+)/update/(?P<pk>[0-9]+)/$', PostUV.as_view(), name='post_update'),
url(r'^(?P<slug>[-\w]+)/delete/(?P<pk>[0-9]+)/$', PostDeleteView.as_view(), name='post_delete'),
]
models.py
#python_2_unicode_compatible
class Blog(models.Model): # 유저 당 하나
name = models.CharField(max_length=20)
description = models.CharField(max_length=30)
image = models.ImageField(upload_to='blog/profile')
create_date = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True,allow_unicode=True)
# 블로그 생성한 시각
# 저장 경로: MEDIA_ROOT/blog/projile/xxx.jpg 파일 저장
# DB 필드 'MEDIA_URL/blog/profile/xxx.jpg' 문자열 저장
user = models.OneToOneField(User)
class Meta:
ordering = ['-create_date']
# 생성된 날짜의 내림차순으로 정렬
def __str__(self):
return self.name
#python_2_unicode_compatible
class Post(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
create_date = models.DateTimeField(auto_now_add=True)
modify_date = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User)
slug = models.SlugField(allow_unicode=True,default='slug')
class Meta :
ordering = ['-create_date']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',args=(self.id,))
# post.get_absolute_url args
# 객체가 지칭하는 url 반환
def get_previous_post(self):
return self.get_previous_by_create_date()
#create_date 기준으로 이전 포스트 반환
# get_previous_by_column 내장객체 호출
def get_next_post(self):
return self.get_next_by_create_date()
#python_2_unicode_compatible
class Reple(models.Model):
content = models.TextField()
user = models.ForeignKey(User)
Post = models.IntegerField() # post_id
create_date = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-create_date']
def __str__(self):
return self.content
It's my first time writing, so I don't know how to Indent. Sorry
And if my code is not effective, tell me how to fix it.
thank you!
It might be easier to write the view from scratch as a function, but you can also override the existing post method to return additional data.