Humbly asking for the community’s help; looked through earlier similar questions, but they didn’t help me.
I’m creating a forum project (as a part of a site), it’s structure is roughly: “Forum → subforums → topics → comments”. So, opening “site/forum” page, there would be several forum sections (“subforums”), clicking on each of them will lead to the list of corresponding topics (not all of them, but only made within that subforum specially - that’s what I mean by the word “corresponding” here); clicking on every topic will lead to the topic’s content and its corresponding comments.
I use slug, class-based-views, get_absolute_url method in models, and “app_name” in urls.py.
In my DB there are 2 filler topics, one for “News” subforum, another for “Production” subforum. For some certain long time I’ve tried to organize the slug for topics the way like (f"topic-{self.id}"), but failed in that undertaking, thus choosing the slugify option.
And now, when the problem with slug was solved, and forum page became achievable, filled with buttons for subforums, after clicking on subforum buttons to check whether the list of topics is displayed there, django debug returns an error:
“django.urls.exceptions.NoReverseMatch: Reverse for ‘topic’ with keyword arguments ‘{‘topic_slug’: ‘topic-scenario-timing-plan’}’ not found. 1 pattern(s) tried: [‘forum/(?P<subforum_slug>[-a-zA-Z0-9_]+)/(?P<topic_slug>[-a-zA-Z0-9_]+)/\Z’]”
And I am kind of ignorant of where from this problem proceeds. ‘topic-scenario-timing-plan’ is a slug of one of the filler topics I’ve created. If I click on any of subforums’ buttons, the same error will be displayed.
Below are corresponding files, which might be useful to look at:
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify
from .consts import *
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
surname = models.CharField(max_length=32, default='')
name = models.CharField(max_length=32, default='')
email = models.EmailField(max_length=254, blank=True, unique=True)
bio = models.TextField(max_length=500, default="Write a couple of words about yourself")
avatar = models.ImageField(default=None, blank=True, max_length=255)
status = models.CharField(max_length=25, blank=True, default='')
slug = models.SlugField()
age = models.IntegerField(verbose_name='Возраст', null=True, blank=True)
gender = models.CharField(verbose_name='Пол', max_length=32, choices=Genders.GENDER_CHOICES, default="H", blank=True)
reputation = models.IntegerField(verbose_name='Репутация', default=0)
def __str__(self):
return f'{self.user} profile'
def get_absolute_url(self):
return reverse('forum:user_profile', kwargs={'profile_slug': self.slug})
def save(self, *args, **kwargs):
if not self.id:
self.slug = slugify(self.user.username)
return super(Profile, self).save(*args, **kwargs)
class Subforum(models.Model):
title = models.CharField(verbose_name='Название', max_length=32, choices=Theme.THEME_CHOICES, default=1)
slug = models.SlugField(default='News')
objects = models.Manager()
class Meta:
ordering = ['title']
verbose_name = 'Разделы форума'
verbose_name_plural = 'Разделы форума'
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.id:
self.slug = slugify(self.title)
return super(Subforum, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('forum:subforum', kwargs={'subforum_slug': self.slug})
class Topic(models.Model):
subject = models.CharField(verbose_name='Заголовок', max_length=255, unique=True)
first_comment = models.TextField(verbose_name='Сообщение', max_length=2000, default='')
slug = models.SlugField(default='', unique=True, max_length=25, editable=False)
subforum = models.ForeignKey('Subforum',
verbose_name='Раздел',
on_delete=models.CASCADE,
related_name='subforum')
creator = models.ForeignKey(User,
verbose_name='Создатель темы',
on_delete=models.SET('deleted'),
related_name='creator')
created = models.DateTimeField(auto_now_add=True)
closed = models.BooleanField(default=False)
objects = models.Manager()
class Meta:
ordering = ['id']
verbose_name = 'Обсуждения'
verbose_name_plural = 'Обсуждения'
def __str__(self):
return self.subject
def save(self, *args, **kwargs):
if not self.id:
self.slug = f'topic-{slugify(self.subject)}'
return super(Topic, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('forum:topic', kwargs={'topic_slug': self.slug})
class Comment(models.Model):
topic = models.ForeignKey('Topic',
verbose_name='Тема',
on_delete=models.CASCADE,
related_name='topic')
author = models.ForeignKey(User,
verbose_name='Комментатор',
on_delete=models.SET('deleted'),
related_name='author')
content = models.TextField(verbose_name='Текст', max_length=2000)
created = models.DateTimeField(verbose_name='Дата публикации', auto_now_add=True)
updated = models.DateTimeField(verbose_name='Дата изменения', auto_now=True)
objects = models.Manager()
class Meta:
ordering = ['created']
verbose_name = 'Комментарии'
verbose_name_plural = 'Комментарии'
def __str__(self):
return f'Post of {self.topic.subject} is posted by {self.author.username}.'
views.py:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from core.views import menu
from .forms import AddTopicForm, AddCommentForm
from .models import Subforum, Topic, Comment, Profile
from .utils import DataMixin
class SubForumListView(ListView):
model = Subforum
context_object_name = 'subforum_list'
template_name = "forum/forum.html"
def get_context_data(self, **kwargs):
subforums = Subforum.objects.all()
context = {'subforums': subforums}
return context
class TopicListView(ListView):
model = Topic
template_name = "forum/subforum.html"
slug_url_kwarg = 'subforum_slug'
context_object_name = 'subforum'
def get_context_data(self, **kwargs):
topics = Topic.objects.all()
context = {'topics': topics}
return context
class ShowTopic(DetailView):
model = Topic
template_name = "forum/topic.html"
slug_url_kwarg = 'topic_slug'
context_object_name = 'topic'
def get_context_data(self, topic_slug, **kwargs):
topic = get_object_or_404(Topic, slug=topic_slug)
comments = Comment.objects.filter(topic=topic)
comments_number = len(Comment.objects.filter(topic=topic))
context = {'menu': menu,
'topic': topic,
'comments': comments,
'comm_num': comments_number}
return context
class AddTopic(LoginRequiredMixin, DataMixin, CreateView):
form_class = AddTopicForm
template_name = 'forum/addtopic.html'
page_title = 'Создание новой темы'
class AddComment(LoginRequiredMixin, DataMixin, CreateView):
form_class = AddCommentForm
template_name = 'forum/addcomment.html'
page_title = 'Оставить комментарий'
success_url = reverse_lazy('topic')
class UpdateComment(LoginRequiredMixin, DataMixin, UpdateView):
form_class = AddCommentForm
template_name = 'forum/addcomment.html'
page_title = 'Редактировать комментарий'
success_url = reverse_lazy('topic')
class UserProfile(DetailView):
model = Profile
template_name = "profile.html"
urls.py:
from django.urls import path
from forum.views import *
app_name = 'forum'
urlpatterns = [
path('', SubForumListView.as_view(), name='forum'),
path('<slug:subforum_slug>/', TopicListView.as_view(), name='subforum'),
path('<slug:subforum_slug>/<slug:topic_slug>/', ShowTopic.as_view(), name='topic'),
path('<slug:subforum_slug>/add-topic/', AddTopic.as_view(), name="add_topic"),
path('<slug:subforum_slug>/<slug:topic_slug>/add-comment/', AddComment.as_view(), name="add_comment"),
path('<slug:subforum_slug>/<slug:topic_slug>/edit/<int:id>/', UpdateComment.as_view(), name="edit_comment"),
]
If some additional files/information are necessary to solve the problem, I’d be glad to provide them.
Thank you for your help in advance.