HTMX - Reverse for 'notes_submit' with arguments '('',)' not found. 1

I created a small app to make notes and initial test of AI LLM POC.

Entire app works as intended except when editing notes. Always throws a dreaded “NoReverseMatch” (added word doc of the entire error).
NOTE: I deleted the all the *.html files and views.py functions, urls.py etc. and started all over again copy and pasting the code from another app I have written and used many times as a template. Basically only having to change the namespace, models info etc. Only this app (hyperapp) is having the issue.

The error is in edit_notes.html hx-post=“{% url ‘hyperapp:notes_submit’ item.pk %}”

----------------------- ADDING THE ERROR BCUZ CANNOT FIND ATTACH OPTION ---------------

NoReverseMatch at /hyperapp/edit_notes/55/

Reverse for ‘notes_submit’ with arguments ‘(’‘,)’ not found. 1 pattern(s) tried: [‘hyperapp/notes_submit/(?P[0-9]+)/\Z’]

Request Method: GET
Request URL: http://127.0.0.1:8000/hyperapp/edit_notes/55/
Django Version: 5.0.6
Exception Type: NoReverseMatch
Exception Value: Reverse for ‘notes_submit’ with arguments ‘(’‘,)’ not found. 1 pattern(s) tried: [‘hyperapp/notes_submit/(?P[0-9]+)/\Z’]
Exception Location: C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python Projects\epson.epsonVE\Lib\site-packages\django\urls\resolvers.py, line 851, in _reverse_with_prefix
Raised during: hyperapp.views.edit_notes
Python Executable: C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python Projects\epson.epsonVE\Scripts\python.exe
Python Version: 3.11.9
Python Path: ['C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\enoc_proj’, ‘C:\Program Files\Python311\python311.zip’, ‘C:\Program Files\Python311\DLLs’, ‘C:\Program Files\Python311\Lib’, ‘C:\Program Files\Python311’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages\odf’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages\odf’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages\odf’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages\odf’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages\odf’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages\odf’, 'C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python ’ ‘Projects\epson\.epsonVE\Lib\site-packages\odf’]
Server time: Sun, 21 Jul 2024 12:29:28 -0500

Error during template rendering

In template C:\Users\EAI24909\OneDrive - Epson America\Desktop\Python Projects\epson\.epsonVE\enoc_proj\hyperapp\templates\hyperapp\edit_notes.html, error at line 13

Reverse for ‘notes_submit’ with arguments ‘(’‘,)’ not found. 1 pattern(s) tried: [‘hyperapp/notes_submit/(?P[0-9]+)/\Z’]

3 {{ form.content.errors }}
4
5 {{ form.created_date }}
6 {{ form.created_date.errors }}
7
8
9
10 <button type=“button”
11 class=“btn-sm btn-outline-success”
12 hx-headers=‘{“X-CSRFToken”: “{{ csrf_token }}”}’
13 hx-post=“{% url ‘hyperapp:notes_submit’ item.pk %}”

I will add the relevant code below for viewing.

urls.py

from django.urls import path, include
from django.contrib import admin
from django.contrib.auth import login, logout
from django.urls import reverse

from . import views

app_name = 'hyperapp'   

urlpatterns = [
  path("hyperapp/", views.hyperindex, name="hyperhome"),
  path("add", views.add_notes_view, name="add_notes_view"),
]
htmxpatterns = [
  path("delete/<int:pk>/", views.delete_notes_view, name="delete_notes"),
  path('edit_notes/<int:pk>/', views.edit_notes, name='edit_notes'),
  path('notes_submit/<int:pk>/', views.notes_submit, name='notes_submit'),   
  path('setOrderby/', views.setOrderby, name='setOrderby'), 
  path('search_results_view/', views.search_results_view, name='search_results_view'),     
]
urlpatterns += htmxpatterns

models.py

from django.db import models

class NotesModel(models.Model):
  content = models.CharField(max_length=1000,blank=True,null=True)
  created_date = models.DateTimeField(auto_now_add=True)
  
  def __str__(self):
        return self.content

views.py


from .models import NotesModel

_ORDBY = ('-id')                                             # setting default global var for order_by
_ITEMS_PER_PAGE = 4   

def hyperindex(request):
  notes = NotesModel.objects.all().order_by(_ORDBY) # new
  paginator = Paginator(notes, _ITEMS_PER_PAGE)    
  page_number = request.GET.get('page')          
  page_obj = paginator.get_page(page_number) 
  template = 'hyperapp/hyperindex.html'     
  return render(request, template, {'page_obj': page_obj, 'count': notes.count()})
    
@require_http_methods(["GET", "POST"])
def setOrderby(request):
    template = 'hyperapp/lists.html'  
    global _ORDBY                                               # get global var ready for change
    if request.method == "POST":
        if request.POST.get("wordup", None) is None:
            _ORDBY = ('-id')                                    # something happened with request so reset to (-id) 
        else:
            inputtxt = request.POST.get('wordup')
            if inputtxt == "order_by_content":
                if _ORDBY == ('content'):                         # check to see if _ORDBY already equals 'title'
                    _ORDBY = ('-id')                            # change order by now
                else:
                    _ORDBY = ('content')
            else:                                               # default _ORDBY = ('-id') if inputtxt had an issue
                _ORDBY = ('-id')
            notes = NotesModel.objects.all().order_by(_ORDBY)         # NOTE: _ORDBY is a variable 
            paginator = Paginator(notes, _ITEMS_PER_PAGE)    
            page_number = request.GET.get('page')           
            page_obj = paginator.get_page(page_number)      
    return render(request, template, {'page_obj': page_obj, 'count': notes.count()})

@require_http_methods(["GET", "POST"])
def add_notes_view(request):
  content = request.POST.get('note_content')                                               # new
  note = NotesModel.objects.create(content=content)                                   # new
  note.save()                                                                         # new  
  notes = NotesModel.objects.all().order_by(_ORDBY)                                   # new
  paginator = Paginator(notes, _ITEMS_PER_PAGE)                                       # new 
  page_number = request.GET.get('page')                                               # new
  page_obj = paginator.get_page(page_number)                                          # new
  template = 'hyperapp/lists.html'                                                    # new
  return render(request, template, {'page_obj': page_obj, 'count': notes.count()})    # new


def delete_notes_view(request,pk):
  note = NotesModel.objects.get(pk=pk)    # changed from id=pk to pk=pk
  note.delete()
  notes = NotesModel.objects.all().order_by(_ORDBY)
  paginator = Paginator(notes, _ITEMS_PER_PAGE)       
  page_number = request.GET.get('page')              
  page_obj = paginator.get_page(page_number)        
  template = 'hyperapp/lists.html'
  return render(request, template, {'page_obj': page_obj, 'count': notes.count()}) 


class NoteForm(forms.ModelForm):
    class Meta:
        model = NotesModel
        exclude = []
         
        
@require_http_methods(["GET", "POST"])
def edit_notes(request, pk):
    note = NotesModel.objects.get(pk=pk)
    context = {}
    context['note'] = note
    print(pk)
    context['form'] = NoteForm(initial={
        'content': note.content,
        'created_date' : note.created_date                
    })
    print("JOHN", context)
    template = 'hyperapp/edit_notes.html'
    return render(request, template, context)


@require_http_methods(["GET", "POST"])
def notes_submit(request, pk):    # changed edit_notes_submit  to notes_submit
    print("notes_submit")
    context = {}
    note = NotesModel.objects.get(pk=pk)
    context['note'] = note
    print("context jbh:", context)
    
    if request.method == 'POST':
          print("post")
          form = NoteForm(request.POST, instance=note)
          if form.is_valid():
            form.save()
            notes = NotesModel.objects.all().order_by(_ORDBY)
          else:
            template = 'hyperapp/edit_note.html'
            return render(request, template, context)
    template = 'hyperapp/note_row.html'
    return render(request, template, context)
  
  
@require_http_methods(["GET", "POST"])
def search_results_view(request):
    query = request.GET.get('search', '')   		        # NOTE: ‘search’  is from the input control in search html file
    note = NotesModel.objects.all()
    
    if query:
        #notes = note.filter(content__icontains=query)        # NOTE: 'title' is field from models.py
        notes = note.filter(content__startswith=query)
        paginator = Paginator(notes, _ITEMS_PER_PAGE)    
        page_number = request.GET.get('page')           
        page_obj = paginator.get_page(page_number)      
    else:                                                   # if we get here then there was no query match 
        notes = []
        notes = NotesModel.objects.all().order_by(_ORDBY)
        paginator = Paginator(notes, _ITEMS_PER_PAGE)    
        page_number = request.GET.get('page')           
        page_obj = paginator.get_page(page_number)      
        template = 'hyperapp/lists.html'
        return render(request, template, {'page_obj': page_obj, 'count': notes.count()}) 
    context = {'page_obj': page_obj}                         
    template = 'hyperapp/lists.html'
    return render(request, template, context)

base.html

{% load static %}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{% block title %}{% endblock %}</title>
    <!-- Bootstrap 5 css -->
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
  </head>
  <body>
        <div class="container mt-5">
            {% block content %}
            
            {% endblock %}
        </div>
      <script src="{% static 'js/bootstrap.bundle.min.js' %}"></script>

      <script src="{% static 'js/htmx.min.js' %}"></script>

      {% block js_script %}
      {% endblock %}

      <script>
        document.body.addEventListener('htmx:configRequest', (event) => {
          event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
        })
      </script>
  </body>
</html>

hyperindex.html

{% extends 'hyperapp/base.html' %}
{# load static #}                   

{% block title %} Home {% endblock %}
{% block content %}

<h3 class="my-5">Notes</h3>
{% csrf_token %}
<!--  this section is for the search box -->
<input class="form-control" type="search"
       name="search" placeholder="Begin Typing To Search for a title..." 
       hx-get="{% url 'hyperapp:search_results_view' %}" 
       hx-trigger="keyup changed delay:500ms"
       hx-target="#notes_results">   
<br>

<form hx-post="{% url 'hyperapp:add_notes_view' %}" hx-target="#notes_results" class="mx-auto" hx-on::after-request="this.reset()">
  {% csrf_token %}
  <div class="mb-3 row align-items-center">
      <label for="noteText" class="col-auto col-form-label">Enter new notes here: </label> 
      <div class="col-6">
        <input type="text" name="note_content" class="form-control" placeholder="Enter notes here">
      </div>

      <div class="col-auto">
          <button class="btn-sm btn-outline-primary">Add Notes</button>
      </div>
  </div>
</form>

<div id="notes_results">
    {% include 'hyperapp/lists.html' %}
</div>

 <!-- chat col -->
 <div class="col">
  <div class="card">
    <div class="card-header">
      eAI Chat
    </div>
    <div class="card-body">
      <div class="overflow-auto p-3 bg-light" style="width: 450px; height: 600px;">
      <p id="results"></p>
      </div>
    </div>
      
    <div class="card-footer text-body-secondary">
      <form action="">

      <input type="text" name="search_query" class="form-control" placeholder="Ask A question"
      hx-post="{% url 'hyperapp:ask_llm' %}"
      hx-target="#results"
      hx-trigger="keyup changed delay:5s"
      hx-swap="beforeend"
      >
      <br>
      <button type="reset" class="btn btn-danger">Clear</button> 
      <button type="Submit" class="btn btn-primary"
      hx-post="{% url 'hyperapp:ask_llm' %}"
      hx-target="#results"
      hx-swap="beforeend"

      >Send</button> 
      </form>
    
    </div>
    
  </div> 
</div>
</div>
</div>

{% endblock %}

{% block js_script %}
<script>
  document.body.addEventListener('htmx:configRequest', (event) => {
      event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
  })
</script>
{% endblock %}

lists.html


{% if page_obj %}   
<!-- NOTE: this option on the next ** line overflow-y: auto; ** is what allows scrollable tables but when I 
 inserted the code for pagination this feature seems to disable itself. interesting-->
<div class="table-responsive" style="height: 500px; overflow-y: auto;">
  <table  class="table table-striped w-100 d-block d-md-table">
    <form>
    <thead>
        <div>
          <input type="hidden" id="txword" name="wordup" value="order_by_content">  
        <th>
          <a class="" href="" 
            hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
            hx-post="{% url 'hyperapp:setOrderby' %}"
            hx-trigger="click"
            hx-target="#notes_results"
            hx-include="[name='wordup']"
            >Content</a>
        </th>
        </div>
        
        <th>Created</th>
    </thead>
    </form>
    <tbody>
      {# for item in notes #}
      {% for item in page_obj %}
            {% include 'hyperapp/note_row.html' %}
      {% endfor %}
    </tbody>
  </table>
</div>


    <div class="btn-group" role="group" aria-label="Item pagination">
        {% if page_obj.has_previous %}
            <a href="?page={{ page_obj.previous_page_number }}" class="btn btn-outline-primary">&laquo;</a>
        {% endif %}
        {% for page_number in page_obj.paginator.page_range %}
            {% if page_obj.number == page_number %}
                <button class="btn btn-outline-primary active">
                    <span>{{ page_number }} <span class="sr-only">(current)</span></span>
                </button>
            {% else %}
                <a href="?page={{ page_number }}" class="btn btn-outline-primary">
                    {{ page_number }}
                </a>
            {% endif %}
        {% endfor %}
        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}" class="btn btn-outline-primary">&raquo;</a>
        {% endif %}
    </div>
    <div>Total record count: {{ count }}</div>

{% else %}
<h5>Currently, you don't have any notes. Or there were no search matches.</h5>
{% endif %}

note_row.html

<tr>
  <td style="word-wrap: break-word;min-width: 60px;max-width: 60px;">{{ item.content }}</td>
  <td style="word-wrap: break-word;min-width: 50px;max-width: 50px;">{{ item.created_date }}</td>
 
  <td>
    <button type="button" 
    class="btn-sm btn-outline-danger"  
    hx-get="{% url 'hyperapp:delete_notes' item.pk %}"
    hx-target="#notes_results"
    hx-confirm="Are you sure you wish to delete?"  
    style="cursor: pointer;">
    DEL
    </button>
 
    <button type="button"
    class="btn-sm btn-outline-warning" 
    hx-get="{% url 'hyperapp:edit_notes' item.pk %}" 
    hx-target="closest tr" 
    hx-swap="outerHTML"
    style="cursor: pointer;">
    Edit
    </button>
  </td>

</tr>

edit_notes.html

<tr>
  <td style="word-wrap: break-word;min-width: 60px;max-width: 60px;">{{ form.content }}
      {{ form.content.errors }} 
  </td>
  <td>{{ form.created_date }}
      {{ form.created_date.errors }} 
  </td>
  
<td>
  <button type="button" 
  class="btn-sm btn-outline-success" 
  hx-post="{% url 'hyperapp:notes_submit' item.pk %}" 
  hx-target="closest tr" 
  hx-swap="outerHTML" 
  hx-include="closest tr" >
  Save
  </button>

  <button type="button" 
  class="btn-sm btn-outline-dark" 
  hx-get="{% url 'hyperapp:notes_submit' item.pk %}" 
  hx-target="closest tr" 
  hx-swap="outerHTML">
  Cancel
  </button>
</td> 
</tr>

in edit_notes.html, item.pk must be int obejct.
but you send ‘’.

check it.

Thank u for your reply.
Pk is set in urls.py to an int
int:pk
Item is part of a loop when filling the table with data.
Can you tell me what i need to do to fix this?

The thing thats confusing is this code i wrote is a code framework for crud + search and i have used it many times. In fact 2 of the other apps in this very project uses this code. I only change the namespace, views.py function names, database related etc etc. The skeleton is the same. I was so frustrated the other day i deleted this app and rebuilt it from copying 1 of thise apps and still fails in the exact same html page and code line. Never seen this.
Please advise
Thank you
John

check your edit_notes.html and find why item.pk is ‘’.

<tr>
  <td style="word-wrap: break-word;min-width: 60px;max-width: 60px;">{{ form.content }}
      {{ form.content.errors }} 
  </td>
  <td>{{ form.created_date }}
      {{ form.created_date.errors }} 
  </td>
  
<td>
  <button type="button" 
  class="btn-sm btn-outline-success" 
  item.pk:<<{{item.pk}}>>
  # hx-post="{% url 'hyperapp:notes_submit' item.pk %}" 
  hx-target="closest tr" 
  hx-swap="outerHTML" 
  hx-include="closest tr" >
  Save
  </button>

  <button type="button" 
  class="btn-sm btn-outline-dark" 
  hx-get="{% url 'hyperapp:notes_submit' item.pk %}" 
  hx-target="closest tr" 
  hx-swap="outerHTML">
  Cancel
  </button>
</td> 
</tr>

I appreciate your help on this, but the problem ended being caused by me puting the incorrect name in the for loop for lists.html include.
Thank you