ValueError at /book/add Field 'id' expected a number but got 'add' --- django

A working site was bringing the collection of books with its content displayed But when I add a function def addbook(request): it gives me a problem this:

ValueError at /book/add Field 'id' expected a number but got 'add'.

enter image description here

in -- all_book.html:

{% extends 'base.html' %}

    {% block content %}
          <h1>kljgf</h1>
          <a href ="{% url 'addbook' %}">Add Book</a>
          {% for book in books %}
            <h3>
              <a href = "{% url 'detail_book' book.id %}">{{book.namebook}}</a>
            </h3>
            <hr>
          {% endfor %}
    {% endblock content %}

in views:

def detail_book(request, id):
    boo = book.objects.get(id=id)
    context = {'book' : boo} 
    return render(request, 'detail_book.html',  context)

def addbook(request):
    book_form = book_form()
    context = {'form' : book_form}
    return render(request, 'add_book.html',  context)

in url:

  path('book/<id>', views.detail_book, name="detail_book"),
  path('book/add', views.addbook, name="addbook"),

in add_book.html

{% extends 'base.html' %}

{% block content %}
      <h1>add book </h1>
      <form method="POST">
          {% csrf_token %}
          {{form}}
      </form>
{% endblock content %}

The path book/add is ambiguous - it is being parsed as book/<id> with id = 'add'

You need to either change one of the two paths to resolve the ambiguity, or put the path for book/add before book/<id> so that the URL dispatcher matches it first.

Your urls.py will look from top to bottom for matches to your URL, so when you click /add the first match it finds is the ID query that expects a numerical ID.

Flipping the order of those two URL paths so it checks for add first, and ID only if add doesn't match should solve your problem.

This is happening because you haven't provided a type for so django is assuming 'add' is an id.

While you could fix this by changing the order to look for defined strings first, it might be more pythonic to make the difference explicit. In urls.py, add 'int' to the variable parameter as in the docs

  path('book/<int:id>', views.detail_book, name="detail_book"),
  path('book/add', views.addbook, name="addbook"),

Now the order doesn't matter, as integers will be assumed to be ids and non-integers can be other views.

Back to Top