I am working on a blog app that is pretty much finished, but I have a problem with submission of an invalid form.
If I use hx-post=“{{ request.path }}” for the form submission it works as expected, but when I try to use named url (which is the recommended approach from what I’ve seen) I get the following server error when the form is invalid:
django.urls.exceptions.NoReverseMatch: Reverse for ‘blog-post-detail’ with arguments ‘(’‘,)’ not found. 1 pattern(s) tried: [‘blog/(?P<url_identifier>[-a-zA-Z0-9_]+)\Z’]
[12/Jun/2024 13:03:44] “POST /blog/petrlaska-pecina HTTP/1.1” 500 151029
Everything works well if the form is valid. What am I doing wrong? Should I keep using “request.path” for the form action, as it was not causing any problems?
This is my form snippet:
<form hx-post="{% url 'blog:blog-post-detail' blogpost.url_identifier %}"
hx-target="#comment-section"
hx-swap="innerHTML"
id="comment-form"
novalidate
>
{% csrf_token %}
{% if messages %}
{% for message in messages %}
<p id="msg">{{ message }}</p>
{% endfor %}
{% endif %}
{% if comments %}
<h3>Komentari ({{ comments.count }})</h3>
{% else %}
<h3>Komentari (0)</h3>
{% endif %}
{% if user.is_authenticated %}
{{ comment_form.content }}
{% if comment_form.content.errors %}
{% for error in comment_form.content.errors %}
<p class="error-msg">{{ error }}</p>
{% endfor %}
{% endif %}
{% else %}
{{ comment_form.content }}
{% if comment_form.content.errors %}
{% for error in comment_form.content.errors %}
<p class="error-msg">{{ error }}</p>
{% endfor %}
{% endif %}
<p class="input-field">
{{ comment_form.name }}
</p>
{% if comment_form.name.errors %}
{% for error in comment_form.name.errors %}
<p class="error-msg">{{ error }}</p>
{% endfor %}
{% endif %}
<p class="input-field">
{{ comment_form.email }}
</p>
{% if comment_form.email.errors %}
{% for error in comment_form.email.errors %}
<p class="error-msg">{{ error }}</p>
{% endfor %}
{% endif %}
{% endif %}
<button type="submit">Pošalji</button>
</form>
This is the view that handles it:
class BlogPostDetailView(DetailView):
model = BlogPost
template_name = "blog/blog_detail.html"
# Setting the path parameter
slug_field = 'url_identifier'
slug_url_kwarg = 'url_identifier'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.filter(blog_post=self.object).order_by('-created_on')
# Initialize "name" and "email" fields based on the cookies
name = self.request.COOKIES.get('blog_comment_name', '')
email = self.request.COOKIES.get('blog_comment_email', '')
if not self.request.user.is_authenticated:
# Checking if post has already been liked by the reader
liked_posts = self.request.COOKIES.get('liked_blog_posts', '').split(',')
context['liked'] = str(self.object.pk) in liked_posts
# Setting the reader's name and email based on whether they have already commented on the post
context['comment_form'] = CommentForm(initial={'name': name, 'email': email})
else:
context['comment_form'] = CommentForm(user=self.request.user)
# oembed to iframe conversion for CKeditor5
context['content'] = transform_oembed(self.object.content)
return context
def get(self, request, *args, **kwargs):
self.object = self.get_object()
# Increment the view count
self.object.views += 1
self.object.save(update_fields=['views'])
context = self.get_context_data(object=self.object)
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = CommentForm(request.POST, user=self.request.user)
if form.is_valid():
comment = form.save(commit=False)
# Set default values for admin users
if self.request.user.is_authenticated:
comment.author = self.request.user
comment.name = self.request.user.first_name + ' ' + self.request.user.last_name
comment.email = self.request.user.email
comment.blog_post = self.object
comment.save()
comments = Comment.objects.filter(blog_post=self.object).order_by('-created_on')
comment_form = CommentForm(user=self.request.user)
# Set predefined comment form values for name and email for non-authenticated readers if stored in cookies
if not self.request.user.is_authenticated:
name = self.request.COOKIES.get('blog_comment_name', '')
email = self.request.COOKIES.get('blog_comment_email', '')
comment_form = CommentForm(initial={'name': name, 'email': email})
# messages.success(request, 'Komentar uspešno dodat')
ctx = self.get_context_data()
ctx.update({'comments': comments, 'comment_form': comment_form})
response = render(request, 'blog/partials/comment_section.html', ctx)
# Set name and email cookie values for readers who comment for the first time
if not self.request.user.is_authenticated:
if 'blog_comment_name' not in request.COOKIES:
response.set_cookie('blog_comment_name', request.POST['name'], max_age=157_784_760)
if 'blog_comment_email' not in request.COOKIES:
response.set_cookie('blog_comment_email', request.POST['email'], max_age=157_784_760)
return response
else:
comments = Comment.objects.filter(blog_post=self.object).order_by('-created_on')
ctx = {'comments': comments, 'comment_form': form}
return render(request, 'blog/partials/comment_section.html', ctx)
project level urls:
urlpatterns = [
path("admin/", admin.site.urls),
path("blog/", include("blog.urls")),
path("", views.return_to_blog),
]
app level urls:
app_name = 'blog'
urlpatterns = [
path("", views.BlogPostListView.as_view(), name="blog-post-list"),
path("<slug:url_identifier>", views.BlogPostDetailView.as_view(), name="blog-post-detail"),
]