Django - ListView - list assigned images to the post - python

Hello I would like to list all images which were added to my post in my Blog application.
Models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = RichTextField(blank=True, null=True)
class PostImage(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE, related_name='postimages')
image = models.ImageField(upload_to='gallery/')
I guess I should override the get_queryset method but dont know how. Any ideas? Thanks.
EDIT:
Views.py
class PostGalleryView(ListView):
model = PostImage
template_name = 'blog/gallery.html'
context_object_name = 'images'
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
paginate_by = 10
def get_queryset(self):
public_posts = Post.objects.all()
return public_posts

Related

how do i include get_absolute_url in my success_url of a class view

How do i include the get_absolute_url defined in the model in the class based view?
models.py:
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="comments")
name = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(default="This is the Body of a Comment.")
date_added = models.DateField(auto_now_add=True)
time_added = models.DateTimeField(auto_now_add=True)
date_updated = models.DateField(auto_now=True)
time_updated = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = "Post Comments"
ordering = ["-time_updated"]
def __str__(self):
return self.post.title + " | " + self.name.username
def get_absolute_url(self):
return f"/blogs/post/{self.post.slug}"
views.py:
class DeleteCommentView(DeleteView):
model = Comment
template_name = "delete_comment.html"
success_url = (refer the get_absolute_url)
You can override the .get_success_url() method [Django-doc]:
class DeleteCommentView(DeleteView):
model = Comment
template_name = 'delete_comment.html'
def get_success_url(self):
return self.object.get_absolute_url()
But I think you are here using the .get_absolute_url() method the wrong way: see the note below.
Note: The get_absolute_url() method [Django-doc] should return a canonical URL, that means that for two different model objects the URL should be different and thus point to a view specific for that model object. You thus should not return the same URL for all model objects.

How to solve the NOT NULL constraint failed Error in Django

I am getting an IntegrityError when I want to save a new course on my e-learning website. Of course, I have searched for a similar solution on StackOverflow but I couldn't find an appropriate way for my solution.
here are my models
UserAccount Model
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserAccount(AbstractUser):
email = models.EmailField(
max_length=255, verbose_name='email', unique=True)
username = models.CharField(max_length=255, unique=True)
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
Course Model
from django.db import models
from accounts.models import UserAccount
class Course(models.Model):
owner = models.ForeignKey(
UserAccount, related_name='courses_created', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
slug = models.SlugField()
description = models.TextField()
cover_photo = models.ImageField(upload_to="cover/", null=True, blank=True)
Also, my course form is here
class CourseForm(forms.ModelForm):
class Meta:
model = Course
fields = ['curriculum', 'title', 'description', 'cover_photo']
widgets = {
'description': forms.Textarea(attrs={'rows': 3})
}
So in my view, I like to send the list of my courses to the template and also my CourseForm() using the get_context_data method. The code is bellow
My class-based view
class OwnerListMixin(object):
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(owner=self.request.user)
class OwnerCourseMixin(OwnerListMixin, LoginRequiredMixin, PermissionRequiredMixin):
model = Course
fields = ['curriculum', 'title', 'description', 'cover_photo']
success_url = reverse_lazy('manage_course_list')
class ManageCourseListView(OwnerCourseMixin, ListView):
template_name = "courses_app/manage/course/list.html"
permission_required = "courses_app.view_course"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = CourseForm()
return context
but when I render the form in my template to save a new course I get the following Error
IntegrityError at /create/
NOT NULL constraint failed: courses_app_course.owner_id
CREATE VIEW
class CourseCreateView(OwnerCourseMixin, CreateView):
permission_required = "courses_app.add_course"
template_name = "courses_app/manage/course/form.html"
success_url = reverse_lazy("manage_course_list")
You need to set the user as the owner what currently is not happening. The form is being saved with the fields you have set. There are multiple ways of adding the user. You could do it this way.
from django.shortcuts import redirect
class CourseCreateView(OwnerCourseMixin, CreateView):
permission_required = "courses_app.add_course"
template_name = "courses_app/manage/course/form.html"
success_url = reverse_lazy("manage_course_list")
def form_valid(self, form):
instance = form.save(commit=False)
instance.owner = self.request.user
instance.save()
return redirect(self.get_success_url())

How to bind a comment form to one pot without a choice (Django)

When writing a comment under the article, it becomes possible to
choose which post to bring the comment to. How to make comments
automatically attach to the post under which it is written.
**views.py**
class AddCommentView(CreateView):
model = Comment
template_name = 'main/post_detail.html'
form_class = CommentForm
#fields = '__all__'
success_url = reverse_lazy('barbers')
**models.py**
class Post(models.Model):
photo = models.ImageField(upload_to='media/photos/',null=True, blank=True)
name_barber = models.CharField(max_length=30, null=True, blank=True)
description = models.TextField()
def __str__(self):
return self.description[:10]
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=30)
body = models.TextField(null=True)
add_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.post, self.name)
**forms.py**
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ( 'post', 'name', 'body')
You can remove the post field from the CommentForm:
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ('name', 'body')
In the path, you specify the primary key of the post to bind the comment to:
path('<int:post_pk>/comment', AddCommentView.as_view(), name='comment')
then in the AddCommentView, you can link the object to the post represented by this primary key in the .form_valid(…) method [Django-doc]:
class AddCommentView(CreateView):
model = Comment
template_name = 'main/post_detail.html'
form_class = CommentForm
success_url = reverse_lazy('barbers')
def form_valid(self, form):
form.instance.post_id = self.kwargs['post_pk']
return super().form_valid(form)

Update model each time a view is generated in django

I'm trying to update my an instance of Post model each time a view PostDetail is generated. So far I've tried multiple approaches but none of them worked. I know that there is ready solution (django-hitcounter) but I would like to write one myself so I can understand what is happening.
The goal there is to add 1 to post.views each time user accesses PostDetail view.
models.py
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='blog_posts')
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
views = models.IntegerField(default=0)
class Meta:
ordering = ['-created_on']
views.py
class PostDetail(generic.DetailView):
model = Post
template_name = 'blog/post_detail.html'
urls.py
urlpatterns = [
path('<slug:slug>/', views.PostDetail.as_view(), name='post_detail'),
]
Once you've got to the point where Django can return a response (eg: it's found the Post object successfully etc...) - you can increment your view count for the object then and proceed to returning the response, so if you change your view to be:
class PostDetail(generic.DetailView):
model = Post
template_name = 'blog/post_detail.html'
def render_to_response(self, context, **kwargs):
self.object.views += 1
self.object.save()
return super().render_to_response(context, **kwargs)

how to play with ordering in class based view

I'm using class based view and for instance
class PostListByMostViewedView(ListView):
model = Post
template_name = 'community/mostviewed_home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-views']
paginate_by = 5
Models.py
class Post(models.Model):
views = models.PositiveIntegerField(default=0)
then posts are listed by view. but
I have different model
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
I want to order by the number of post.
I thought this would work
ordering = ['-post.comment_set.count']
but this fails
no such column: post.comment_set.count
You can .annotate(..) [Django-doc] the Post objects with the number of items in the comment_set, and then .order_by(..) [Django-doc] that annotation:
from django.db.models import Count
class PostListByMostViewedView(ListView):
model = Post
queryset = Post.objects.annotate(
ncomments=Count('comment')
).order_by('-ncomments')
template_name = 'community/mostviewed_home.html'
context_object_name = 'posts'
paginate_by = 5
The nice thing is that every Post object from the queryset now has an extra attribute ncomments that contains the number of comments.

Categories