Issue
I'm trying to add comments to my blog, but I have this error and I cannot figure out why.
Error:
NoReverseMatch at /2024/01/01/lesson-1/
Reverse for 'post_comment' with arguments '('',)' not found. 1 pattern(s) tried: ['(?P<year>[0-9]+)/(?P<month>[0-9]+)/(?P<day>[0-9]+)/(?P<lesson>[-a-zA-Z0-9_]+)/comment/\\Z']
with highlight on:
<form action="{% url 'lang_learning_app:post_comment' post.id %}" method="post">
url.py
urlpatterns = [
...
path('<int:year>/<int:month>/<int:day>/<slug:lesson>/', views.lesson_detail, name='lesson_detail'),
path('<int:year>/<int:month>/<int:day>/<slug:lesson>/comment/', views.post_comment, name='post_comment'),
...]
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['name', 'email', 'body']
models.py
class Lesson(models.Model):
class Status(models.TextChoices):
DRAFT = 'DF', 'Draft'
PUBLISHED = 'PB', '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, related_name='blog_posts')
body = models.TextField()
tags = TaggableManager()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=2, choices=Status.choices, default=Status.DRAFT)
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('lang_learning_app:lesson_detail', args=[self.publish.year, self.publish.month, self.publish.day, self.slug])
class Comment(models.Model):
post = models.ForeignKey(Lesson,
on_delete=models.CASCADE,
related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Meta:
ordering = ['created']
indexes = [
models.Index(fields=['created']),
]
def __str__(self):
return f'Comment by {self.name} on {self.post}'
views.py
@require_POST
def post_comment(request, post_id):
post = get_object_or_404(Lesson, id=post_id, status=Lesson.Status.PUBLISHED)
comment = None
# A comment was posted
form = CommentForm(data=request.POST)
if form.is_valid():
# Create a Comment object without saving it to the database
comment = form.save(commit=False)
# Assign the post to the comment
comment.post = post
# Save the comment to the database
comment.save()
return render(request, 'lessons/comment.html', {'post': post, 'form': form, 'comment': comment})
comment_form.html
<h2>Add a new comment</h2>
<form action="{% url 'lang_learning_app:post_comment' post.id %}" method="post">
{{ form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Add comment"></p>
</form>
lesson_detail.html
{% with comments.count as total_comments %}
<h2>
{{ total_comments }} comment{{ total_comments|pluralize }}
</h2>
{% endwith %}
{% for comment in comments %}
<div class="comment">
<p class="info">
Comment {{ forloop.counter }} by {{ comment.name }}
{{ comment.created }}
</p>
{{ comment.body|linebreaks }}
</div>
{% empty %}
<p>There are no comments yet.</p>
{% endfor %}
{% include "lessons/comment_form.html" %}
Not sure why I'm getting this error, I have followed instructions from book Django by example. I have made some adjustments for my blog, instead of post I have used lesson. Do you have any idea why I'm getting this error?
Thanks in advance!
Solution
Reverse for 'post_comment' with arguments '('',)' not found
is usually a telltale that a context variable used in the {% url %}
tag is empty.
Django {% url %}
tags struggle with the concept of None
or "optional" arguments. The context variables are resolved first, meaning that if the attribute doesn't exist, it renders to a default empty string ''
.
{% url %}
and the reverse()
machinery then try to resolve a URL using the empty string. If you think about it, this would create a nonsensical URL, like app/posts//comments
. There aren't really any hidden assumptions made by Django here; it expects URLs and arguments to match precisely.
What this means for you is that you have to pass all the URL parameters that are expected by the path()
entry, as defined in urls.py
and/or urlpatterns
. Instead of:
<form action="{% url 'lang_learning_app:post_comment' post.id %}" method="post">
You need something like:
<form action="{% url 'lang_learning_app:post_comment' post.published.year post.published.month post.published.day post.slug %}" method="post">
Now, you may be looking at that and thinking, "that would be dreadful to write in more than one template", and you'd be correct in my opinion. Long, complicated {% url %}
tags are difficult to maintain. When you run into this, consider resolving the URL in Python using Django's reverse()
function. It's the same as what {% url %}
does under the hood, but you have more control over it in Python versus the template.
Answered By - Supra621
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.