Can't add comment form in Django web application - django

I have a trouble adding form-group (I believe it's bootstrap class).
The form-group doesn't do anything at all, or maybe it's a problem with form.author and form-body variables!?
More simply, I need UI comment section (now only I can add and edit comments from django admin page). Some code:
post_details.html
<article class="media content-section">
<form action="/post/{{ post.slug }}/" method="post">
{% csrf_token %}
<div class="form-group">
{{ form.author }}
</div>
<div class="form-group">
{{ form.body }}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<ul>
{% for comment in post.comments.all %}
<p>
<b>#{{ comment.author }}</b>
<small>{{ comment.created_date }} </small>
</p>
<p> {{ comment.text }}</p>
<hr>
{% if comment.replies.all %}
<ul>
{% for reply in comment.replies.all %}
<p>{{ reply.text }}</p>
<hr>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
<ul>
</article>
forms.py
from django import forms
class CommentForm(forms.Form):
author = forms.CharField(
max_length=60,
widget=forms.TextInput(
attrs={"class": "form-control", "placeholder": "Your Name"}
),
)
body = forms.CharField(
widget=forms.Textarea(
attrs={"class": "form-control", "placeholder": "Leave a comment!"}
)
)
views.py
def comment(request):
form = CommentForm()
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment(
author=form.cleaned_data["author"],
body=form.cleaned_data["body"],
post=post,
)
comment.save()
context = {"post": post, "comments": comments, "form": form}
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment(
author=form.cleaned_data["author"],
body=form.cleaned_data["body"],
post=post
)
comment.save()
comments = Comment.objects.filter(post=post)
context = {
"post": post,
"comments": comments,
"form": form,
}
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(User, on_delete=models.CASCADE)
text = models.TextField()
created_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.text
EDIT:
urls.py
from django.urls import path
from django.conf.urls import include, url
from . import views
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView, UserPostListView
urlpatterns = [
#Blog section
path("", PostListView.as_view(), name='blog-home'),
path("user/<str:username>", UserPostListView.as_view(), name='user-posts'),
path('post/<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
path("posts/new/", PostCreateView.as_view(), name='post-create'),
path("post/<slug:slug>/update/", PostUpdateView.as_view(), name='post-update'),
path("post/<slug:slug>/delete/", PostDeleteView.as_view(), name='post-delete'),
path("about/", views.about, name="blog-about"),
path("<category>/", views.blog_category, name="blog_category"),
]
I really need something like this (tried to follow this tutorial, but nothing works well :
My comment section:

I've looked into that tutorial and implemented myself. Here goes the answer:
urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.blog_index, name="blog_index"),
path("<slug:slug>/", views.post_detail, name="post_detail"),
path("<category>/", views.blog_category, name="blog_category"),
]
models.py
from django.db import models
from django.utils.text import slugify
class Category(models.Model):
name = models.CharField(max_length=20)
class Post(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField("Category", related_name="posts")
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
class Comment(models.Model):
author = models.CharField(max_length=60)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey("Post", on_delete=models.CASCADE)
post_detail.html
{% extends "blog_app/base.html" %}
{% block page_content %}
<div class="col-md-8 offset-md-2">
<h1>{{ post.title }}</h1>
<small>
{{ post.created_on.date }} |
Categories:
{% for category in post.categories.all %}
<a href="{% url 'blog_category' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</small>
<p>{{ post.body | linebreaks }}</p>
<h3>Leave a comment:</h3>
<form action="/blog/{{ post.pk }}/" method="post">
{% csrf_token %}
<div class="form-group">
{{ form.author }}
</div>
<div class="form-group">
{{ form.body }}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<h3>Comments:</h3>
{% for comment in comments %}
<p>
On {{comment.created_on.date }}
<b>{{ comment.author }}</b> wrote:
</p>
<p>{{ comment.body }}</p>
<hr>
{% endfor %}
</div>
{% endblock %}
views.py
def post_detail(request, slug):
post = Post.objects.get(slug=slug)
comments = Comment.objects.filter(post=post)
form = CommentForm()
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment(
author=form.cleaned_data["author"],
body=form.cleaned_data["body"],
post=post,
)
comment.save()
context = {"post": post, "comments": comments, "form": form}
return render(request, "blog_app/post_detail.html", context)
Edit
I've changed the code to support slug field generation from the title. I'm not handling exception, thus you gonna have look into it by yourself. Good luck.

I think the problem is you're using a Form and not a ModelForm.
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['author', 'text']
...

In your file views.py you have duplicated code and you don't have the return
statement:
return render(request, "post_details.html", context)

Related

Django blog post_update function not working as intended

I am following a youtube channel to create a blog. I am stuck at post_update function. when i try to update the post the comment is getting updated, which should not happen in this scenario. where am I going wrong?
def post_update(request, id):
title = 'Update'
post = get_object_or_404(Post, id=id)
form = PostForm(
request.POST or None,
request.FILES or None,
instance=post)
author = get_author(request.user)
if request.method == "POST":
if form.is_valid():
form.instance.author = author
form.save()
return redirect(reverse("post-detail", kwargs={
'id': form.instance.id
}))
context = {
'title': title,
'form': form
}
return render(request, "post_create.html", context)
views.py
from django.db.models import Count, Q
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render, get_object_or_404, redirect, reverse
from .forms import CommentForm, PostForm
from .models import Post, Author
from marketing.models import Signup
def get_author(user):
qs= Author.objects.filter(user=user)
if qs.exists():
return qs[0]
return None
def search(request):
queryset = Post.objects.all()
query = request.GET.get('q')
if query:
queryset = queryset.filter(
Q(title__icontains = query) |
Q(overview__icontains = query)
).distinct()
context = {
'queryset' : queryset
}
return render(request, 'search_results.html', context)
def get_category_count():
queryset = Post \
.objects \
.values('categories__title') \
.annotate(Count('categories__title'))
return queryset
def index(request):
featured = Post.objects.filter(featured=True)
latest = Post.objects.order_by('-timestamp')[:3]
if request.method == "POST":
email = request.POST['email']
new_signup = Signup()
new_signup.email = email
new_signup.save()
context = {
'object_list' : featured ,
'latest' :latest
}
return render(request, 'index.html', context)
def blog(request):
category_count = get_category_count()
#print(category_count)
most_recent = Post.objects.order_by('-timestamp')[:3]
post_list = Post.objects.all()
paginator = Paginator(post_list, 4)
page_request_var ='page'
page = request.GET.get(page_request_var)
try:
paginated_queryset = paginator.page(page)
except PageNotAnInteger:
paginated_queryset = paginator.page(1)
except EmptyPage:
paginated_queryset = paginator.page(paginator.num_pages)
context = {
'queryset' : paginated_queryset,
'most_recent' : most_recent,
'page_request_var': page_request_var,
'category_count': category_count
}
return render(request, 'blog.html', context)
def post(request, id):
most_recent = Post.objects.order_by('-timestamp')[:3]
category_count = get_category_count()
post = get_object_or_404(Post, id=id)
form = CommentForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
form.instance.user= request.user
form.instance.post = post
form.save()
return redirect(reverse("post-detail", kwargs={
'id' : post.id
}))
context ={
'form' : form,
'post' : post,
'most_recent' : most_recent,
'category_count': category_count
}
return render(request, 'post.html', context)
def post_create(request):
title = 'Create'
form = PostForm(request.POST or None, request.FILES or None)
author = get_author(request.user)
if request.method == "POST":
if form.is_valid():
form.instance.author= author
form.save()
return redirect(reverse("post-detail", kwargs={
'id' : form.instance.id
}))
context = {
'title': title,
'form' : form
}
return render(request, "post_create.html", context)
def post_update(request, id):
title = 'Update'
post = get_object_or_404(Post, id=id)
form = PostForm(
request.POST or None,
request.FILES or None,
instance=post)
author = get_author(request.user)
if request.method == "POST":
if form.is_valid():
form.instance.author = author
form.save()
return redirect(reverse("post-detail", kwargs={
'id': form.instance.id
}))
context = {
'title': title,
'form': form
}
return render(request, "post_create.html", context)
def post_delete(request, id):
post = get_object_or_404(Post, id=id)
post.delete()
return redirect(reverse("post-list"))
Whatever is present in content is getting updated as comment which should not happen I am not able to understand the flow. And also <P> tag is visible which I have not used in html.
post_create.html
{% extends 'base.html ' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-4 offset-4 mb-5 mt-5">
<h3>{{ title }} an Article</h3>
{{ form.media }}
<form method="POST" action="." enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" type="submit">Submit</button>
</form>
</div>
{% endblock content %}
model.py
from django.db import models
from django.contrib.auth import get_user_model
from django.urls import reverse
from tinymce import HTMLField
User = get_user_model()
# class PostView(models.Model):
# user = models.ForeignKey(User, on_delete=models.CASCADE)
# post = models.ForeignKey('Post', on_delete=models.CASCADE)
# def __str__(self):
# return self.user.username
class Author(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
profile_picture = models.ImageField()
def __str__(self):
return self.user.username
class Category(models.Model):
title = models.CharField(max_length = 20)
def __str__(self):
return self.title
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
content = HTMLField()
comment_count = models.IntegerField(default =0)
view_count = models.IntegerField(default =0)
author = models.ForeignKey(Author, on_delete = models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
previous_post = models.ForeignKey('self', related_name = 'previous', on_delete = models.SET_NULL, blank=True, null = True)
next_post = models.ForeignKey('self', related_name = 'next', on_delete = models.SET_NULL, blank=True, null = True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={
'id': self.id
})
def get_update_url(self):
return reverse('post-update', kwargs={
'id': self.id
})
def get_delete_url(self):
return reverse('post-delete', kwargs={
'id': self.id
})
#property
def get_comments(self):
return self.comments.all().order_by('-timestamp')
class Comment(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
content = models.TextField()
#profile_picture = models.ImageField()
post = models.ForeignKey(Post, related_name='comments', on_delete = models.CASCADE)
def __str__(self):
return self.user.username
post.html
{% extends 'base.html ' %}
{% load static %}
{% block content %}
<style>
.post-body img {
width: 100%;
}
</style>
<div class="container">
<div class="row">
<!-- Latest Posts -->
<main class="post blog-post col-lg-8">
<div class="container">
<div class="post-single">
<div class="post-thumbnail"><img src="{{ post.thumbnail.url }}" alt="..." class="img-fluid"></div>
<div class="post-details">
<div class="post-meta d-flex justify-content-between">
<div class="category">
{% for cat in post.categories.all %}
{{ cat }}
{% endfor %}
</div>
<div>
Update
Delete
</div>
</div>
<h1>{{ post.title }}<i class="fa fa-bookmark-o"></i></h1>
<div class="post-footer d-flex align-items-center flex-column flex-sm-row"><a href="#" class="author d-flex align-items-center flex-wrap">
<div class="avatar"><img src="{{ post.author.profile_picture.url }}" alt="..." class="img-fluid"></div>
<div class="title"><span>{{ post.author.user.username }}</span></div></a>
<div class="d-flex align-items-center flex-wrap">
<div class="date"><i class="icon-clock"></i> {{ post.timestamp|timesince }} ago</div>
<div class="views"><i class="icon-eye"></i> {{ post.view_count }}</div>
<div class="comments meta-last"><i class="icon-comment"></i>{{ post.comment_count }}</div>
</div>
</div>
<div class="post-body">
{{ post.content|safe }}
</div>
<div class="posts-nav d-flex justify-content-between align-items-stretch flex-column flex-md-row">
{% if post.previous_post %}
<a href="{{ post.previous_post.get_absolute_url }}" class="prev-post text-left d-flex align-items-center">
<div class="icon prev"><i class="fa fa-angle-left"></i></div>
<div class="text"><strong class="text-primary">Previous Post </strong>
<h6>{{ post.previous.title }}</h6>
</div>
</a>
{% endif %}
{% if post.next_post %}
<a href="{{ post.next_post.get_absolute_url }}" class="next-post text-right d-flex align-items-center justify-content-end">
<div class="text"><strong class="text-primary">Next Post </strong>
<h6>{{ post.next.title }}</h6>
</div>
<div class="icon next"><i class="fa fa-angle-right"> </i></div>
</a>
{% endif %}
</div>
<div class="post-comments">
<header>
<h3 class="h6">Post Comments<span class="no-of-comments">{{ post.comments.count }}</span></h3>
</header>
{% for comment in post.get_comments %}
<div class="comment">
<div class="comment-header d-flex justify-content-between">
<div class="user d-flex align-items-center">
<div class="image">
{% if comment.user.author %}
<img src="{{ comment.user.author.profile_picture.url }}" alt="NA" class="img-fluid rounded-circle">
{% else %}
<img src="{% static 'img/user.svg' %}" alt="..." class="img-fluid rounded-circle">
{% endif %}
</div>
<div class="title"><strong>{{ comment.user.username }}</strong><span class="date">{{ comment.timestamp|timesince }} ago</span></div>
</div>
</div>
<div class="comment-body">
<p>{{ comment.content }}</p>
</div>
</div>
{% endfor %}
</div>
{% if request_user.is_authenticated %}
<div class="add-comment">
<header>
<h3 class="h6">Leave a reply</h3>
</header>
<form method ="POST" action="." class="commenting-form">
{% csrf_token %}
<div class="row">
<div class="form-group col-md-12">
{{ form }}
</div>
<div class="form-group col-md-12">
<button type="submit" class="btn btn-secondary">Submit Comment</button>
</div>
</div>
</form>
</div>
{% endif %}
</div>
</div>
</div>
</main>
{% include 'sidebar.html' with most_recent=most_recent category_count=category_count %}
</div>
</div>
{% endblock %}

get_absolute_url creates blank link

get_absolute_url doesn't create url. Clicking in title of the post must lead to detail of the post. While I manually create url in address bar as blog/2020/1/3/check-text, it works. What could be the possible problem? Is it something to do with python version?
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date='publish')
author = models.ForeignKey(User,
on_delete=models.CASCADE)
body = models.TextField()
publish = models.DateTimeField(default = timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
objects = models.Manager() # the default manager
published = PublishedManager() # our custom manager
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail', args = [
self.publish.year,
self.publish.month,
self.publish.day,
self.slug,
])
views.py
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator, PageNotAnInteger,\
EmptyPage
from django.views.generic import ListView
from .models import Post
from .forms import EmailPostForm
from django.core.mail import send_mail
class PostListView(ListView):
queryset = Post.published.all()
context_object_name = 'posts'
paginate_by = 3
template_name = 'blog/post/list.html'
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.PostListView.as_view(), name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',
views.post_detail,
name='post_detail'),
path('<int:post_id>/share/',
views.post_share, name='post_share'),
]
list.html
{% extends 'blog/base.html' %}
{% block title %}My Blog{% endblock%}
{% block content %}
<h1>My Blog</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
<!-- {% include '../pagination.html' with page=posts %} -->
{% include '../pagination.html' with page=page_obj %}
{% endblock %}
detail.html
{% extends 'blog/base.html' %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<h1>{{ post.title }}</h1>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|linebreaks }}
<p>
<a href="{% url 'blog:post_share' post.id %}">
Share this post
</a>
</p>
{% endblock %}
see href is empty

How to add slug in Django Web-application

Here is the problem: I'm trying to 'fresh' my django web blog, so instead of having /post/2/ I want to have slugged link that's exactly like my title (smth like this: /post/today-is-friday
Here is some code, I've tried couple of things, but there is nothing working:
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
from django.template.defaultfilters import slugify
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
categories = models.ManyToManyField('Category', related_name='posts')
image = models.ImageField(upload_to='images/', default="images/None/no-img.jpg")
slug= models.SlugField(max_length=500, unique=True, null=True, blank=True)
def save(self, *args, **kwargs):
self.url= slugify(self.title)
super(Post, self).save(*args, **kwargs)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Category(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
urls.py
from django.urls import path
from django.conf.urls import include, url
from . import views
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView, UserPostListView
urlpatterns = [
#Blog section
path("", PostListView.as_view(), name='blog-home'),
path("user/<str:username>", UserPostListView.as_view(), name='user-posts'),
path("<slug:slug>/", PostDetailView.as_view(), name='post-detail'),
path("post/new/", PostCreateView.as_view(), name='post-create'),
path("<slug:slug>/update/", PostUpdateView.as_view(), name='post-update'),
path("<slug:slug>/delete/", PostDeleteView.as_view(), name='post-delete'),
path("about/", views.about, name="blog-about"),
path("<category>/", views.blog_category, name="blog_category"),
]
user_posts.html(this is for accessing blog post itself)
{% extends 'blog/base.html' %}
{% block content %}
<h1 class='mb-3'>Post by {{ view.kwargs.username }} ({{ page_obj.paginator.count }})</h1>
{% for post in posts %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}" alt="">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2 author_title" href="{% url 'user-posts' post.author.username %}">#{{ post.author }}</a>
<small class="text-muted">{{ post.date_posted|date:"N d, Y" }}</small>
<div>
<!-- category section -->
<small class="text-muted">
Categories:
{% for category in post.categories.all %}
<a href="{% url 'blog_category' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</small>
</div>
</div>
<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content|slice:200 }}</p>
</div>
</article>
{% endfor %}
{% endblock content %}
post_form.html(It's for creating a new post, have trouble with redirecting after post created)
{% extends 'blog/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Blog Post</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
If you are going to change the value of the slug field before saving, you can use signals.
Also the slugify method of django is located in django.utils.text not django.template.defaultfilters.
urls.py
# ...
path('post/<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
# ...
models.py
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils.text import slugify
import string
class Post(models.Model):
# ...
slug= models.SlugField(max_length=500, unique=True, null=True, blank=True)
# do not override save method here
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug=None):
if new_slug is not None:
slug = new_slug
else:
slug = slugify(instance.title)
class_ = instance.__class__
qs_exists = class_.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = f"{slug}-{random_string_generator(size=5)}"
return unique_slug_generator(instance, new_slug=new_slug)
return slug
#receiver(pre_save, sender=Post)
def post_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
Those two functions, unique_slug_generator and random_string_generator, together will guaranty that you won't have same slug on two posts, even if the title of those posts are same! (it will add some randomly generated string at the end)
Edit
In your html template for user_posts.html, replace
<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
with
<h2><a class="article-title" href="{% url 'post-detail' post.slug %}">{{ post.title }}</a></h2>
Also, in your view (not template) of post_form, you should override get_success_url like this:
def get_success_url(self):
return reverse('post-detail', kwargs={'slug': self.object.slug})
Edit 2 (for more clarification)
First, we need a url for each post, we implement it as:
path('post/<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
Next, you should change your previous links to the post-detail. These include your 1)template links and 2)links in the views/models:
In your templates, wherever you have {% url 'post-detail' post.pk %}, you should change that to {% url 'post-detail' post.slug %}.
and in your views/models, you should change reverse('post-detail', kwargs={'pk': self.pk}) tp reverse('post-detail', kwargs={'slug': self.slug}) (not self.object.slug)

Django creating update post function

I want to create a post update/edit function but I have a problem. When I click "Update" button there is no error but there is no change. I think reason of that a mistake that I made in models.py but I can not figure it out. And here is my code
models.py
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
.
.
.
def get_update_url(self):
return reverse('post:post_update', kwargs={'slug': self.slug})
views.py
def post_update(request, slug):
if not request.user.is_authenticated():
return Http404()
post = get_object_or_404(Post, slug=slug)
form = PostForm(request.POST or None, request.FILES or None, instance=post)
if form.is_valid():
form.save()
messages.success(request, "Updated")
return HttpResponseRedirect(get_absolute_url())
context = {
'form': form
}
return render(request, "blog/post_update.html", context)
post_update.html
{% extends 'blog/base.html' %}
{% load crispy_forms_tags %}
{% block body %}
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>Form</h1>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{{ form.media }}
<input class="btn btn-primary" type="submit" value="Create post">
</form>
</div>
</div>
</div>
{% endblock %}
post_detail.html
//update link
<p >update</p>
urls.py
url(r'^(?P<slug>[\w-]+)/update/$', post_update, name="update"),
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'text',)
Where is my mistake? What can I do?

invalid literal for int() with base 10: 'a'

I am trying to create a comment model for a post in django.I want to print the user name along with the comment.
This is my comment model
class Comment(models.Model):
item = models.ForeignKey('app.Item', related_name='comments')
user = models.ForeignKey('auth.User', blank=True, null=True)
text = models.TextField()
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
This is my view
def add_comment_to_post(request, pk):
item = get_object_or_404(Item, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.user = user.username
comment.item = item
comment.save()
return redirect('item_detail', pk=item.pk)
else:
form = CommentForm()
return render(request, 'app/add_comment_to_post.html', {'form': form}
)
This is my html code
{% for comment in item.comments.all %}
{% if user.is_authenticated or comment.approved_comment %}
<div class="comment">
<div class="date">
{{ comment.created_date }}
{% if not comment.approved_comment %}
<a class="btn btn-default" href="{% url 'comment_remove' pk=comment.pk %}"><span class="glyphicon glyphicon-remove"></span></a>
<a class="btn btn-default" href="{% url 'comment_approve' pk=comment.pk %}"><span class="glyphicon glyphicon-ok"></span></a>
{% endif %}
</div>
<p> {{comment.user}} <p>
<p>{{ comment.text|linebreaks }}</p>
</div>
{% endif %}
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}