I am making a Django blog, and I encountered this error. When you press submit, this error shows up:
Reverse for 'post_detail' not found. 'post_detail' is not a valid view function or pattern name.
If you want to see the error yourself, go to mayfly404.com, click on a post, and then try to comment. Here is my code:
blog/views.py
from django.shortcuts import render, redirect
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin
from django.urls import reverse
from django.views import View
from django.views.generic import (
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView
)
from .models import Post, Comment
from .forms import CommentForm
def home(request):
context = {
'posts': Post.objects.all()
}
return render(request, 'blog/home.html', context)
class PostListView(ListView):
model = Post
template_name = 'blog/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-date_posted']
class PostComment(SingleObjectMixin, FormView):
model = Post
form_class = CommentForm
template_name = 'blog/post_detail.html'
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super().post(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super(PostComment, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def form_valid(self, form):
comment = form.save(commit=False)
comment.post = self.object
comment.save()
return super().form_valid(form)
def get_success_url(self):
post = self.get_object()
return reverse('post_detail', kwargs={'pk': post.pk}) + '#comments'
class PostDisplay(DetailView):
model = Post
template_name = 'blog/post_detail.html'
context_object_name = 'post'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = CommentForm()
return context
class PostDetailView(View):
def get(self, request, *args, **kwargs):
view = PostDisplay.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = PostComment.as_view()
return view(request, *args, **kwargs)
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Post
fields = ['title', 'content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = Post
success_url = '/'
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
def about(request):
return render(request, 'blog/about.html', {'title': 'About'})
blog/urls.py
from django.contrib import admin
from django.contrib.auth import views as auth_views
from django.urls import path, include
from users import views as user_views
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('register/', user_views.register, name='register'),
path('profile/', user_views.profile, name='profile'),
path('profile/<int:pk>/', user_views.profile, name='profile_pk'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
path('', include('blog.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
blog/forms.py
from django.forms import ModelForm
from django.core.exceptions import ValidationError
from .models import Comment
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ['name', 'comment']
def __init__(self, *args, **kwargs):
"""Save the request with the form so it can be accessed in clean_*()"""
self.request = kwargs.pop('request', None)
super(CommentForm, self).__init__(*args, **kwargs)
def clean_name(self):
"""Make sure people don't use my name"""
data = self.cleaned_data['name']
if not self.request.user.is_authenticated and data.lower().strip() == 'samuel':
raise ValidationError("Sorry, you cannot use this name.")
return data
blog/templates/blog/post_detail.html
{% extends "blog/base.html" %}
{% block content %}
<head>
<!-- Ezoic Code -->
<script src="//www.ezojs.com/basicads.js?d=mayfly404.com" type="text/javascript"></script>
<!-- Ezoic Code -->
</head>
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ object.author.profile.image.url }}" alt="{{ object.author }}">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="#">{{ object.author }}</a>
<small class="text-muted">{{ object.date_objected }}</small>
{% if object.author == user %}
<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'post-update' object.id %}">Update Post</a>
<a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'post-delete' object.id %}">Delete Post</a>
{% endif %}
</div>
<h2 class="article-title">{{ object.title }}</h2>
<p class="article-content">{{ object.content|safe }}</p>
<img src="{{ post.image }}" width="250px" onerror="this.style.display='none'">
</div>
</article>
<h2 id="comments">Comments</h2>
{% for comment in post.comment_set.all %}
<b>{{ comment.name }}</b> said <b>{{ comment.created_on|timesince }} ago</b>
<p>{{ comment.comment }}</p>
{% empty %}
<p>Feel free to leave the first comment!</p>
{% endfor %}
<hr>
<h3>Add a comment</h3>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
{% endblock content %}
The error in more detail: the picture