I have a forum app, its structure is “forum-subforum-topic-comments”, with topics exclusive for every subforum and comments exclusive for every topic.
Finally having implemented the AddTopic/AddComment functional, I faced a problem of links for editing the comment inside the topic (UpdateView) and deleting the comment (DeleteView) being disfunctional. I had written them via <a href="<url_pattern_name>></a>"
, so I re-wrote them with url
tag (including all the parameters from urls’ path; I don’t know whether it is an optimal solution, but it works, at least).
Links have finally become functional and sent me to the edit page, but when I wanted to submit changes, the program returned an error:
TypeError at /forum/<subforum_slug>/topics/<topic_slug>/45/edit_comment/
Field 'id' expected a number but got <Comment: Post of <topic_subject> is posted by <user>.>.
Request Method: POST
Request URL: http://127.0.0.1:8000/forum/<subforum_slug>/topics/<topic_slug>/45/edit_comment/
Django Version: 5.1.1
Exception Type: TypeError
Exception Value:
Field 'id' expected a number but got <Comment: Post of <topic_subject> is posted by <user>.>
Exception Location: D:\<path>\django_project\.venv\Lib\site-packages\django\db\models\fields\__init__.py, line 2125, in get_prep_value
Raised during: forum.views.UpdateComment
Python Executable: D:\PyCharm Community Edition 2024.1.3\PycharmProjects\django_project\.venv\Scripts\python.exe
Python Version: 3.12.3
(<subforum_slug>, <topic_slug>, <topic_subject>, , - my replacements to make it clear)
The string it has received instead somehow repeats the return of my __str__
method in Comment model; I’ve tried to change it into return self.id
, but it returned an error with statement that it wanted a str
object, not int
(which is understandable, as far as it is a __str__
method).
And here I got lost. I’ve googled for it and changed all my "id"s in self.kwargs['']
to "pk"s, but it didn’t help in this case. So I need help from the community.
(I thought that Django would be easier to master)
urls.py:
from django.urls import path
from forum.views import *
app_name = 'forum'
urlpatterns = [
#path('<slug:profile_slug>/', user_profile, name='user_profile'),
path('', SubForumListView.as_view(), name='forum'),
path('<slug:subforum_slug>/', TopicListView.as_view(), name='subforum'),
path('<slug:subforum_slug>/add_topic/', AddTopic.as_view(), name="add_topic"),
path('<slug:subforum_slug>/topics/<slug:topic_slug>/', ShowTopic.as_view(), name='topic'),
path('<slug:subforum_slug>/topics/<slug:topic_slug>/add_comment/', AddComment.as_view(), name="add_comment"),
path('<slug:subforum_slug>/topics/<slug:topic_slug>/<int:pk>/edit_comment/', UpdateComment.as_view(), name="edit_comment"),
path('<slug:subforum_slug>/topics/<slug:topic_slug>/<int:pk>/delete_comment/', DeleteComment.as_view(), name="delete_comment"),
]
views.py:
<...>
class AddComment(LoginRequiredMixin, DataMixin, CreateView):
model = Comment
form_class = AddCommentForm
template_name = 'forum/addcomment.html'
page_title = 'Оставить комментарий'
def get_success_url(self):
return reverse('forum:topic', kwargs={
'subforum_slug': self.kwargs['subforum_slug'],
'topic_slug': self.kwargs['topic_slug']})
def form_valid(self, form):
topic = Topic.objects.get(slug=self.kwargs['topic_slug'])
form.instance.author = self.request.user
form.instance.topic = topic
return super(AddComment, self).form_valid(form)
class UpdateComment(LoginRequiredMixin, DataMixin, UpdateView):
model = Comment
form_class = AddCommentForm
context_object_name = 'comment'
template_name = 'forum/editcomment.html'
page_title = 'Редактировать комментарий'
def get_success_url(self):
return reverse('forum:edit_comment', kwargs={
'subforum_slug': self.kwargs['subforum_slug'],
'topic_slug': self.kwargs['topic_slug'],
'id': self.kwargs['pk']
})
def form_valid(self, form):
topic = Topic.objects.get(slug=self.kwargs['topic_slug'])
comment_id = Comment.objects.get(id=self.kwargs['pk'])
form.instance.author = self.request.user
form.instance.topic = topic
form.instance.id = comment_id
return super(UpdateComment, self).form_valid(form)
class DeleteComment(LoginRequiredMixin, DataMixin, UpdateView):
model = Comment
context_object_name = 'comment'
template_name = 'forum/comment_confirm_delete.html'
page_title = "Удаление комментария"
def get_success_url(self):
return reverse('forum:delete_comment', kwargs={
'subforum_slug': self.kwargs['subforum_slug'],
'topic_slug': self.kwargs['topic_slug'],
'id': self.kwargs['id']
})
def form_valid(self, form):
topic = Topic.objects.get(slug=self.kwargs['topic_slug'])
form.instance.author = self.request.user
form.instance.topic = topic
return super(DeleteComment, self).form_valid(form)
models.py:
<...>
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, 'subforum_slug': self.subforum.slug})
class Comment(models.Model):
topic = models.ForeignKey('Topic',
verbose_name='Тема',
on_delete=models.CASCADE,
related_name='comments')
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}.'
topic.html:
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h1>{{ topic.subject }}</h1>
<div class="container-posts">
<div class="row">
<div class="card-subtitle">Создал: {{ topic.creator }}, дата создания: {{ topic.created }}</div>
<div class="card-subtitle">Всего комментариев в теме: {{ comm_num }}</div>
<div class="container-posts">
<a href="add_comment"><button>Оставить комментарий</button></a>
</div>
<div class="card-body">
<div class="media">
{% if p.photo %}
<img src="{{p.photo.url}}" alt="" width="300" height="300">
{% else %}
<img src="{% static 'core/images/Swr-portrait-aya.png' %}" alt="" width="150" height="150">
{% endif %}
</div>
<h5 class="card-subtitle">{{ topic.creator }}</h5>
<h5 class="card-subtitle">Создан: {{topic.created|date:"d.m.Y H:i"}}</h5>
{% autoescape off %}
<p class="card-text">{{topic.first_comment|linebreaks|truncatewords:200}}</p>
{% endautoescape %}
<a href="{% url 'forum:edit_comment' topic.subforum.slug topic.slug %}">Редактировать</a>
<div class="clear"></div>
<hr>
</div>
<!--Comments section -->
{% for p in comments %}
<div class="card-posts">
<div class="card-body">
<div class="media">
{% if p.photo %}
<img src="{{p.photo.url}}" alt="" width="300" height="300">
{% else %}
<img src="{% static 'core/images/Swr-portrait-aya.png' %}" alt="" width="150" height="150">
{% endif %}
</div>
<h5 class="card-subtitle">{{ p.author }}</h5>
<h5 class="card-subtitle">Создан: {{p.created|date:"d.m.Y H:i"}}</h5>
{% autoescape off %}
<p class="card-text">{{p.content|linebreaks|truncatewords:200}}</p>
{% endautoescape %}
<div class="card-subtitle">
<a href="{% url 'forum:edit_comment' topic.subforum.slug topic.slug p.id %}">Редактировать</a>
<a href="{% url 'forum:delete_comment' topic.subforum.slug topic.slug p.id %}">Удалить</a></div>
<div class="clear"></div>
<hr>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
editcomment.html:
{% extends 'base.html' %}
{% block content %}
<h1>Edit comment</h1>
<div class="container-posts">
<form action="" method="post">
{% csrf_token %}
<div class="form-error">{{ form.non_field_errors }}</div>
{% for f in form %}
<div class="container-posts">
<p><label class="form-label" for="{{ f.id_for_label }}">{{ f.label }}</label>{{ f }}</p>
<div class="form-error">{{ f.errors }}</div>
</div>
{% endfor %}
<p><button type="submit">Edit comment</button></p>
</form>
</div>
{% endblock %}
comment_confirm_delete.html:
{% extends 'base.html' %}
{% block content %}
<h1>Delete topic</h1>
<div class="container-posts">
<form method="post">
{% csrf_token %}
<div class="form-error">{{ form.non_field_errors }}</div>
<p>Are you sure you want to delete "{{ object }}"?</p>
<p><button type="submit">Delete</button></p>
<a href="topic">Cancel</a>
</form>
</div>
{% endblock %}
As always, if any additional info is required, I’m ready to provide it.