Implementing pageviews in Django - python

I am working on a small a small website and I want to display the total views of every object in the detail view. But sincerely, I don't know how to actualise this. Let me post my models.py and views.py
Models.py
class Music(models.Model):
artist = models.CharField(max_length=300)
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(default='', blank=True, unique=True)
thumbnail = models.ImageField(blank=False)
audio_file = models.FileField(default='')
uploaded_date = models.DateTimeField(default=timezone.now)
class Meta:
ordering = ['-uploaded_date']
def save(self):
self.uploaded_date = timezone.now()
self.slug = slugify(self.title)
super(Music, self).save()
def __str__(self):
return self.title + ' by ' + self.artist
def get_absolute_url(self):
return reverse('music:detail', kwargs={'slug': self.slug})
Views.py
return Music.objects.order_by('-uploaded_date')
def detail(request, slug):
latest_posts = Music.objects.order_by('-uploaded_date')[:5]
song = get_object_or_404(Music, slug=slug)
comments = Comment.objects.filter(post=song)
if request.method == 'POST':
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post = song
comment.save()
return HttpResponseRedirect(song.get_absolute_url())
else:
comment_form = CommentForm()
context = {
'latest_posts': latest_posts,
'song': song,
'comments': comments,
'comment_form': comment_form,
}
return render(request, 'music/detail.html', context)

You can add an IntegerField to your Music model called page_views:
class Music(models.Model):
...
page_views = IntegerField(default=0)
Then borrowing from this answer you can increment views for the individual song from your detail view whenever the page is requested:
def detail(request, slug):
latest_posts = Music.objects.order_by('-uploaded_date')[:5]
song = get_object_or_404(Music, slug=slug)
comments = Comment.objects.filter(post=song)
if request.method == 'POST':
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post = song
comment.save()
return HttpResponseRedirect(song.get_absolute_url())
else:
comment_form = CommentForm()
song.update(page_views=F('page_views') + 1) # Add this line here so it's not updated on POST
context = {
'latest_posts': latest_posts,
'song': song,
'comments': comments,
'comment_form': comment_form,
}
return render(request, 'music/detail.html', context)
Note that you may not want to count someone adding a comment through the form as another view for the page, so it's up to you how you define when the count actually gets incremented. This is just a really basic way to count how many times the page is requested.

Related

NOT NULL constraint failed: blog_userpost.user_id

Im trying to create a way for people to post their ideas but is giving me this error:
NOT NULL constraint failed: blog_userpost.user_id. I want the user to have to be registered and login in order to make/read the posts.
views.py:
#create view
#login_required(login_url='login')
def userposts_create_view(request):
form= UserPostForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
form = form.save()
form.save()
return HttpResponseRedirect("/Blog/posts/")
context= {'form': form,
}
return render(request, 'posts/userposts-create-view.html', context)
#list view
#login_required(login_url='login')
def userposts_list_view(request):
allposts= UserPost.objects.all()
context= {'allposts': allposts,
}
return render(request, 'posts/userposts-list-view.html', context)
#detail view
#login_required(login_url='login')
def userposts_detail_view(request, url=None):
post= get_object_or_404(UserPost, url=url)
context= {'post': post,
}
return render(request, 'posts/userposts-detail-view.html', context)
models.py
This are the categories I want the post to have, I can 'create' the post but whenever I submit it gives me the error.
User= settings.AUTH_USER_MODEL
class UserPost(models.Model):
user= models.ForeignKey(User, null=False,editable=False, verbose_name='Usuario', on_delete=models.CASCADE)
title= models.CharField(max_length=500)
content= models.TextField()
categories = models.ManyToManyField(Category, verbose_name='Categorias', blank=True,related_name="articles")
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Creado el ')
updated_at = models.DateTimeField(auto_now=True, verbose_name='Actualizado el ')
def save(self, *args, **kwargs):
super(UserPost, self).save(*args, **kwargs)
forms.py
from django import forms
from .models import UserPost
class UserPostForm(forms.ModelForm):
class Meta:
model= UserPost
fields= ["title", "content","categories"]
One simple way is to use model's manager instead of form.save(). So in your condition (i.e. if form.is_valid()) you can use something like:
def userposts_create_view(request):
form= UserPostForm(request.POST or None)
if form.is_valid():
data = form.cleaned_data
categories = data.pop('categories', None)
user_post = UserPost.objects.create(**data, user=request.user)
if categories:
user_post.categories.add(*categories)
return HttpResponseRedirect("/Blog/posts/")
context= {'form': form}
return render(request, 'posts/userposts-create-view.html', context)

Insert comment form on Post detail page. django- blog app

I have trying this from 2-3 days. I want to insert my comment form on post detail page.
My form is not showing on that page.
I have followed this tutorial for the comment model.
I have another app for account which is used for signup purpose.
model.py
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, 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 __str__(self):
return self.title
def publish(self):
self.published_date = timezone.now()
self.save()
def approved_comments(self):
return self.comments.filter(approved_comment=True)
class Comment(models.Model):
post = models.ForeignKey('Post', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(verbose_name ='Username',max_length=200)
text = models.TextField(verbose_name ='Comment')
email = models.EmailField(default='')
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
view.py
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'blog/add_comment_to_post.html', {'form': form})
#login_required
def comment_approve(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.approve()
return redirect('post_detail', pk=comment.post.pk)
#login_required
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.delete()
return redirect('post_detail', pk=comment.post.pk)
urls.py
path('post/<int:pk>/comment/', views.add_comment_to_post, name='add_comment_to_post'),
path('comment/<int:pk>/approve/', views.comment_approve, name='comment_approve'),
path('comment/<int:pk>/remove/', views.comment_remove, name='comment_remove'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
Please help me out to find a way to insert it in my post_deatil.html.
In case you want the same page to see the post and also add a comment you only need one view like:
def post_details(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'blog/post_details.html', {'form': form, 'post': post})
Then your url will be like:
path('post/<int:pk>/', views.post_details, name='post-details'),
And finally you have to mix both of your templates, first showing the information of the post and on the bottom adding the form.
With that you will be able to delete the add_comment_to_post view and url.

Django - redirect after pressing comment delete

I have a code that deletes comments to from posts.
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.delete()
return redirect('Post-detail', pk=post.pk)
It deletes comments, but it throws error that name 'post' is not defined
I have a same function above in my views.py with the same post.pk that works fine...
#login_required
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.author = request.user
#comment.author.photo = object.author.profile.image.url
comment.save()
return redirect('Post-detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'blog/add_comment_to_post.html', {'form': form})
Comment model
class Comment(models.Model):
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=20)
text = models.TextField(max_length=200)
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
Can someone please explain me, where is the problem?
Is it taking no post.pk but comment.pk?
You can pick pk from comment object like this
comment = get_object_or_404(Comment, pk=pk)
....
return redirect('Post-detail', pk=comment.post_id)

How to display post name on new_comment page

i would like to know how i can display the name of a post at my comment_new page:
views.py
def comment_new(request, pk):
if request.method == "POST":
form = CommentForm(request.POST)
post = get_object_or_404(Post, pk=pk)
if form.is_valid():
comment = form.save(commit=False)
comment.author = request.user
comment.published_date = timezone.now()
comment.post = post
comment.save()
messages.success(request, 'You have successfully provided a comment for this Post.')
return redirect('post_detail', pk=comment.post.pk)
else:
form = CommentForm(request.POST)
return render(request, 'app/comment_new.html', {'form': form})
else:
form = CommentForm()
return render(request, 'app/comment_new.html', {'form': form})
models.py
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(verbose_name="Post Title", max_length=40)
content = models.TextField(verbose_name="Post Content", max_length=5000)
tag = models.CharField(verbose_name="Tags/Meta - (sep. by comma)", max_length=50, blank=True)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE, null=True)
template.html
<a>{{ post.title }}</a>
the attribute title is given. I have no idea why it does not work.
thanks in Advance
I'll assume you want to display the post title when a user is about to add a new comment. I mean, when the request is a GET (display the new message form).
def comment_new(request, pk):
# This line is better here since you'll be working with
# the post instance no matter the request method is POST or GET.
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
# ...
else:
form = CommentForm()
# And here pass post as part of the context to your template.
return render(request, 'app/comment_new.html', {'form': form, 'post': post})

Unable to link Blog Posts to Specific Category Django

I used Tango with Django to create a database containing categories, and I used the Django Girls tutorial to add a blog to the database. Both are working fine, but I have been having trouble linking each blog post to its respective category. Right now, all posts go to my post_list.html page.
If I were doing this from scratch, I would add a new view, add a new template, add a url mapping, and then add a link from the category page. I also am aware that I need to edit my blog post model to contain:
category - models.ForeignKey(Category)
I thought it would be as simple as adding this to my url.py:
url(r'^category/(?P<category_name_slug>[\w\-]+)/post_edit/$', views.add_page, name='add_page'),
However after a few rounds of trying things along these lines, I can't quite get anything to work. I run into error after error. I have tried going through other blog-related tutorials online, and looking at other stack-overflow posts related to things like this, but I am still stuck. I am a newbie to Django; I am pretty sure that's playing a roll in my lack of success too.
Below is the (unmodified) code I have so far. Can someone help me with this?
My models.py
class Post(models.Model):
author = models.ForeignKey('auth.User')
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 __str__(self):
return self.title
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField()
def save(self, *args, **kwargs):
# Uncomment if you don't want the slug to change every time the name changes
#if self.id is None:
#self.slug = slugify(self.name)
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __unicode__(self): #For Python 2, use __str__ on Python 3
return self.name
My urls.py
url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category'),
url(r'^post_list/$', views.post_list, name='post_list'),
url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
url(r'^post/new/$', views.post_new, name='post_new'),
url(r'^post/(?P<pk>[0-9]+)/edit/$', views.post_edit, name='post_edit'),
My views.py
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'rango/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'rango/post_detail.html', {'post': post})
def post_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'rango/post_edit.html', {'form': form})
def post_edit(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'rango/post_edit.html', {'form': form})
Thanks in advance.
I realized I had to have my posts filtered to their respective categories. I also switched over to using class based views. The code is a little cleaner.
class PostListView(DetailView):
model = Category
template_name = 'dicer/post_list.html'
def get_context_data(self, **kwargs):
context = super(PostListView, self).get_context_data(**kwargs)
posts = (
Post.objects.filter(category=self.get_object(),
published_date__lte=timezone.now())
.order_by('published_date')
)
context['posts'] = posts
return context

Categories