Reputation: 385
I have a blog which was running without any error. Different users can register, login, and post articles. Users can write/edit/delete comments on the articles. Previously, the URL of the articles were decided using 'article id'. Later, I read this tutorial and added slug along with id in the URL for every article's Detail View. Then I deleted my old articles since they didn't have any slugs.
After this change, a user can create a comment successfully, but cannot 'edit' or 'delete' any comment. Whenever 'edit' or 'delete' button is pressed, 404 error is shown. See the error image by pressing this link.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/articles/33/comment_edit/
Raised by: articles.views.ArticleDetailView
No article found matching the query
My corresponding files are listed below:
urls.py (inside Articles App directory)
from django.urls import path
from .views import (ArticleListView, ArticleUpdateView, ArticleDetailView, ArticleDeleteView, ArticleCreateView,
CommentCreateView, CommentUpdateView, CommentDeleteView)
urlpatterns = [
path('', ArticleListView.as_view(), name='article_list'),
path('<int:pk>/<str:slug>/edit/', ArticleUpdateView.as_view(), name='article_edit'),
path('<int:pk>/<str:slug>/', ArticleDetailView.as_view(), name='article_detail'),
path('<int:pk>/<str:slug>/delete/', ArticleDeleteView.as_view(), name='article_delete'),
path('new/', ArticleCreateView.as_view(), name='article_new'),
#Comments below
path('<int:pk>/<str:slug>/comment/', CommentCreateView.as_view(), name='comment_new'),
path('<int:pk>/comment_edit/', CommentUpdateView.as_view(), name='comment_edit'),
path('<int:pk>/comment_delete/', CommentDeleteView.as_view(), name='comment_delete'),
]
I have tried and run the website by commenting out the url for comments, i.e., the last three lines above. The error shown is the same. This is strange.
urls.py (inside Project directory)
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('users.urls')),
path('users/', include('django.contrib.auth.urls')),
path('', include('pages.urls')),
path('articles/', include('articles.urls')),
]
views.py (inside Articles App directory)
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, DeleteView, CreateView
from django.urls import reverse_lazy
from .models import Article, Comment
# Create your views here.
class ArticleListView(ListView):
model = Article
template_name = 'article_list.html'
ordering = ['-date']
class ArticleDetailView(DetailView):
model = Article
template_name = 'article_detail.html'
query_pk_and_slug = True
class ArticleUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
model = Article
fields = ('title', 'body',)
template_name = 'article_edit.html'
login_url = 'login'
#def test_func for UserPassesTestMixin
def test_func(self):
obj = self.get_object()
return obj.author == self.request.user
success_message = 'Article was updated successfully!'
class ArticleDeleteView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, DeleteView):
model = Article
template_name = 'article_delete.html'
success_url = reverse_lazy('article_list')
login_url = 'login'
def test_func(self):
obj = self.get_object()
return obj.author == self.request.user
success_message = 'Article was deleted successfully!'
class ArticleCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Article
fields = ('title', 'body')
template_name = 'article_new.html'
login_url = 'login' #for LoginRequiredMixin, overriding default login url at accounts/login
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
success_message = 'Article was created successfully!'
#Now for the feature of adding comments on listview and detailview of articles
class CommentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Comment
fields = ('comment',)
template_name = 'comment_new.html'
login_url = 'login'
query_pk_and_slug = True
def form_valid(self, form):
form.instance.author = self.request.user
form.instance.article = Article.objects.get(pk=self.kwargs['pk'])
return super().form_valid(form)
success_message = 'Comment was posted successfully!'
class CommentUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
model = Comment
fields = ('comment',)
template_name = 'comment_edit.html'
login_url = 'login'
#def test_func for UserPassesTestMixin
def test_func(self):
obj = self.get_object()
return obj.author == self.request.user
success_message = 'Comment was updated successfully!'
class CommentDeleteView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, DeleteView):
model = Comment
template_name = 'comment_delete.html'
success_url = reverse_lazy('article_list')
login_url = 'login'
def test_func(self):
obj = self.get_object()
return obj.author == self.request.user
success_message = 'Comment was deleted successfully!'
models.py (inside Articles App directory)
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
User = get_user_model()
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(
default='',
editable=False,
max_length=255,
)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
kwargs = {
'pk': self.id,
'slug': self.slug
}
return reverse("article_detail", kwargs=kwargs)
def save(self, *args, **kwargs):
value = self.title
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comments')
comment = models.TextField()
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
kwargs = {
'pk': self.article.id,
'slug': self.article.slug
}
return reverse("article_detail", kwargs=kwargs)
The links for creating a comment, editing a comment, and deleting a comment in any html file looks like this:
<a href="{% url 'comment_new' article.pk article.slug %}">Add Comment</a>
<a href="{% url 'comment_edit' comment.pk %}">Edit Comment</a>
<a href="{% url 'comment_delete' comment.pk %}">Delete Comment</a>
In my settings.py file, ALLOWED_HOSTS = ['*']
.
Kindly help me with this problem. I have searched online but didn't find any solution.
Upvotes: 0
Views: 1191
Reputation: 308779
The important part of the error message is
Raised by: articles.views.ArticleDetailView
You are trying to edit a comment at /articles/33/comment_edit/
, but it is matching the URL pattern:
path('<int:pk>/<str:slug>/', ArticleDetailView.as_view(), name='article_detail'),
This gives a 404, because you don't have an article with pk=33 and slug='comment_edit'.
You could fix the issue by moving the CommentUpdateView
above ArticleDetailView
so that it matches first.
Upvotes: 1
Reputation: 7744
Have you added your app name inside settings.py
? Make sure you have added the name in settings.py which resides under the project folder.
Like so,
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app_name',] # <--- WhatEver is called
And also make sure you are using your routes you have defined to access the correct page
Upvotes: 0