I am trying to use Django with HTMX. My task is to do editable row in the link list with HTMX. When I click the edit button in the row, I am getting NoReverseMatch error.
raise NoReverseMatch(msg) django.urls.exceptions.NoReverseMatch: Reverse for 'link_update' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['link/edit/(?P[0-9]+)/\Z'] [17/Oct/2023 12:54:42] "GET /link/edit/97/ HTTP/1.1" 500 118059
I've tried so many methods on stackoverflow but I didn't figure it out. Here my code is:
urls.py in my project
urlpatterns = [
path('', home, name='home'),
path('admin/', admin.site.urls),
path("user/", include("user_profile.urls", namespace="user")),
path("link/", include("link.urls", namespace='link')),
]
urls.py in my link app
from django.urls import path
from link.views import tag_view, category_view, delete_links, delete_link, get_row_view, LinkUpdateView, LinkyListView
app_name = 'link'
urlpatterns = [
path('edit/<int:pk>/', LinkUpdateView.as_view(), name='link_update'),
path('edit/<int:pk>/get_row_view/', get_row_view, name='get_row_view'),
path('tag/<slug:tag_slug>/', tag_view, name='tag_view'),
path('category/<slug:category_slug>/', category_view, name='category_view'),
path('delete/', delete_links, name='delete_links'),
path('delete-item/<int:pk>/', delete_link, name='delete_link'),
path('list', LinkyListView.as_view(), name='link_list_view'),
]
views.py in my link app
def get_row_view(request, pk):
link = LinkUrl.objects.get(pk=pk)
context = dict(
link=link,
)
return render(request, 'link/row.html', context)
class LinkUpdateView(UpdateView):
model = LinkUrl
form_class = LinkModelForm
template_name = 'link/edit_link_form.html'
def get_success_url(self):
return reverse_lazy('link:link_update', kwargs={'pk': self.object.pk})
row.html
<tr id="link_list_{{link.pk}}">
<td>{{ link.title }}</td>
<td>{{ link.get_full_url }}</td>
<td>
<span class="p-1 border fs-12 rounded text-light bg-primary">
<a href="{{ link.category.get_absolute_url }}" class="text-decoration-none text-light">
{{ link.category }}
</a>
</span>
</td>
<td>
{% for shortcode, tags in tags_by_shortcode.items %}
{% if shortcode == link.shortcode %}
{% for tag in tags %}
<li class="list-inline-item border p-1 text-muted fs-12 mb-1 rounded">
<a href="{{ tag.get_absolute_url }}" class="text-decoration-none text-muted">
{{ tag.title }}
</a>
</li>
{% endfor %}
{% endif %}
{% endfor %}
</td>
<td>
<button class="btn btn-warning"
hx-get="{% url 'link:link_update' pk=link.pk %}"
hx-target="#link_list_{{link.pk}}">
Edit
</button>
</td>
<td>
<button
class="btn btn-danger btn-sm float-end"
hx-delete="{% url 'link:delete_link' link.pk %}"
hx-confirm="Are you sure you want to delete this item?"
hx-target="#link_list_{{link.id}}"
hx-swap="outerHTML"> Delete
</button>
</td>
</tr>
edit_link_form.html
<td>
<form hx-post="{% url 'link:link_update' pk=link.pk %}">
{% csrf_token %}
{% load crispy_forms_tags %}
{% for field in form %}
<td colspan="{{ form|length }}">
<div class="form-row">
<div class="form-group col-md-12">
{{ field|as_crispy_field }}
</div>
</div>
</td>
{% endfor %}
<td>
<button class="btn btn-primary" type="submit" hx-get="{% url 'link:get_row_view' pk=link.pk %}" hx-target="#form-container"> Save </button>
</td>
<td>
<button class="btn btn-danger" type="button">Cancel</button>
</td>
</form>
</td>
This part of your error message highlights the problem:
NoReverseMatch: Reverse for 'link_update' with keyword arguments '{'pk': ''}' not found
. Specifically, an empty string is being passed when you call link.pk, rather than the primary_key (id) of the link.Now the problem is not with the
hx-get
attribute inside your edit button; that is working because we can see from your traceback that clicking it makes a get request to the appropriate id (97).So the error is inside the
edit_link_form.html
template, and most likely theform
itself inside itshx-post
attribute.My suspicion is that because this template is rendered by the 'LinkUpdateView' which inherits from 'UpdateView' class, so you are encountering this issue because 'link' does not exist in the context dictionary passed to the template --- instead it is referred to as 'object', which is the default context variable for the UpdateView.
So to fix this, inside
edit_link_form.html
change any reference to link to object (including the save button as well as the form), and hopefully you will be fine now (see below for full code):edit_link_form.html