NoReverseMatch at end of tutorial 4

I have fought this for a week before coming humbly to ask for some help. I did a lookup on tutorial 4, then NoReverseMatch but the search didn’t yield any workable hints after reading the results that turned up.

I added Choice to the admin.py to see if any database errors might exist, but didn’t turn up any. I only have a single question with 3 choices.

Prior to the changes to the view.py and the urls.py shown here, I was getting the same error on line 16 but the exception was saying the dictionary values returned were empty.

NoReverseMatch at /polls/1/ at line 16 in the detail.html is the primary error for before I made the last changes in tutorial 4. ( I know, the definition of insane is repeating the error numerous times … I admit it.)

If any pertinent file is missing, let me know.

Error during template rendering
In template /home/dglenn/Projects/Django/innotest/polls/templates/polls/detail.html, error at line 16
Reverse for 'vote' with arguments '('',)' not found. 1 pattern(s) tried: ['polls/(?P<pk>[0-9]+)/vote/$']
Request Method:	GET
Request URL:	http://127.0.0.1:8000/polls/1/
Django Version:	3.1.6
Exception Type:	NoReverseMatch
Exception Value:	
Reverse for 'vote' with arguments '('',)' not found. 1 pattern(s) tried: ['polls/(?P<pk>[0-9]+)/vote/$']
Exception Location:	/home/dglenn/Projects/Django/innotest/venv/lib/python3.8/site-packages/django/urls/resolvers.py, line 685, in _reverse_with_prefix
Python Executable:	/home/dglenn/Projects/Django/innotest/venv/bin/python
Python Version:	3.8.5
Python Path:	
['/home/dglenn/Projects/Django/innotest',
 '/home/dglenn/Projects/Django/innotest',
 '/home/dglenn/Projects/Django/innotest/polls',
 '/home/dglenn/bin/pycharm/plugins/python/helpers/pycharm_display',
 '/usr/lib/python38.zip',
 '/usr/lib/python3.8',
 '/usr/lib/python3.8/lib-dynload',
 '/home/dglenn/Projects/Django/innotest/venv/lib/python3.8/site-packages',
 '/home/dglenn/bin/pycharm/plugins/python/helpers/pycharm_matplotlib_backend']

detail.html as seen from the error message

6	</head>
7	<body>
8	<h1>{{ question.question_text }}</h1>
9	
10	{% if error_message %}
11	    <p><strong>
12	    {{ error_message }}
13	    </strong></p>
14	{% endif %}
15	
16	<form action="{% url 'polls:vote' question_id %}" method="post">
17	{% csrf_token %}
18	
19	{% for choice in question.choice_set.all %}
20	
21	    <input type="radio" name="choice" id=
22	            "choice{{ forloop.counter }}" value="{{ choice.id }}">
23	    <label for="choice{{ forloop.counter }}">
24	        {{ choice.choice_text }}</label>
25	    <br>

Complete detail.html code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Detail</title>
</head>
<body>
<h1>{{ question.question_text }}</h1>

{% if error_message %}
    <p><strong>
    {{ error_message }}
    </strong></p>
{% endif %}

<form action="{% url 'polls:vote' question_id %}" method="post">
{% csrf_token %}

{% for choice in question.choice_set.all %}

    <input type="radio" name="choice" id=
            "choice{{ forloop.counter }}" value="{{ choice.id }}">
    <label for="choice{{ forloop.counter }}">
        {{ choice.choice_text }}</label>
    <br>

{% endfor %}

<input type="submit" value="Vote">
</form>

</body>
</html>


views.py

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from . models import Choice, Question
# Create your views here.

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]


class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'


class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST["choice"])

    except [KeyError, Choice.DoesNotExist]:
        return render(request, "polls/detail.html", {
                "question": question,
                "error_message": "You didn't select a choice.",
                })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(
                reverse("polls:results", args=(question.id,)))

urls.py

from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
        path("", views.IndexView.as_view(), name="index"),
        path("<int:pk>/", views.DetailView.as_view(), name="detail"),
        path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
        path("<int:pk>/vote/", views.vote, name="vote"),
        ]

Digging down into the local variables active while the exception was raised in the resolvers.py on line 685 unfortunately wasn’t very helpful to me. But I’m sure the forum gurus may have seen this before.

_prefix	
'/'
arg_msg	
"arguments '('',)'"
args	
('',)
candidate_pat	
'/polls/%(pk)s/vote/'
candidate_subs	
{'pk': ''}
converters	
{'pk': <django.urls.converters.IntConverter object at 0x7fe598b56820>}
defaults	
{}
k	
'pk'
kwargs	
{}
lookup_view	
'vote'
lookup_view_s	
'vote'
m	
None
match	
True
msg	
("Reverse for 'vote' with arguments '('',)' not found. 1 pattern(s) tried: "
 "['polls/(?P<pk>[0-9]+)/vote/$']")
n	
None
params	
['pk']
pattern	
'polls/(?P<pk>[0-9]+)/vote/$'
patterns	
['polls/(?P<pk>[0-9]+)/vote/$']
possibilities	
[([('polls/%(pk)s/vote/', ['pk'])],
  'polls/(?P<pk>[0-9]+)/vote/$',
  {},
  {'pk': <django.urls.converters.IntConverter object at 0x7fe598b56820>})]
possibility	
[('polls/%(pk)s/vote/', ['pk'])]
result	
'polls/%(pk)s/vote/'
self	
<URLResolver <URLResolver list> (None:None) '^/'>
text_candidate_subs	
{'pk': ''}
v	
''
1 Like

The error message says it’s this line of the template that has a problem. The args = ('',) says that reverse() is receiving an empty string.

Django templates have a “skip over errors” philosophy (not always helpful, but the idea is it’s best to at least show something to the website visitor). Therefore if you reference a variable that doesn’t exist, it turns it into the empty string.

Your mistake here is that the variable question_id doesn’t exist. Instead, the variable is question.id. This can be seen in the template at the start of tutorial part 4.

Another thing here - this should use parentheses, not square brackets. Be careful with bracket types - they have different meanings! In the current state, when handlign the exception, another exception will occur when Python tries to use the list defined with square brackets.

For example:

In [2]: try:
   ...:     1/0
   ...: except [ZeroDivisionError, ValueError]:
   ...:     pass
   ...:
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-2-53451f7e7a1b> in <module>
      1 try:
----> 2     1/0
      3 except [ZeroDivisionError, ValueError]:

ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-2-53451f7e7a1b> in <module>
      1 try:
      2     1/0
----> 3 except [ZeroDivisionError, ValueError]:
      4     pass
      5

TypeError: catching classes that do not inherit from BaseException is not allowed

Hope these hints help!

—Adam

2 Likes

Adam,

You’re right on the money. I’d been comparing the tutorial code with mine for days and failed to see the trees for the forest. I’ve made both changes and voila, a working app. I’d say it’s embarrassing, but learning is like that. As is your admonishment about the square brackets. My coding knowledge is weak (understatement). My past programs have been so simple I’ve never delved into data types beyond slicing strings and the occasional dict.

You said:

Current software iterations costs are out of reach and only large corporations and governments can afford the technology. I want to create an open source web application on it to benefit everyone, not just the big boys.

I agree wholeheartedly with the philosophy. And I’m glad it’s there. I had no idea of what I was getting into and the hill ahead of me choosing Django. I, very erroneously, thought it be like Joomla but with the ability to used Python code vs PHP (I don’t even want to go there). Yet despite this, Django is the best platform for my project … It will just take a bit longer to settle in, learn it thoroughly to complete the project. But being retired now, so it isn’t like I have hard deadline to meet although sadly I’ve not met my own deadlines. Which make me deeply grateful for the community support I’ve experienced here.

There are areas though I see presented that appear to be violations of PEP 8 such as:

pk=request.POST["choice"]

I’m just in the dark about the logic behind it. I’m going to have to dig deeper into the API to find the answer.

No worries, not embarassing at all. Programming is just one mistake after another.

I don’t recall saying this :confused: But I do agree with the sentiment too, that we should have frameworks that are available to everyone with a low barrier to entry.

The tutorial may not be absolutely PEP8 compliant.

These days most projects I work on use black to format their code to match PEP8, saving brainpower for actually thinking about the code rather than formatting decisions. Check it out.

Adam,

Oddly enough it was a thread in another window. I know how it happened, I had done a paste operation using the ‘normal’ control c and v to paste. The quote I meant to post was the highlight, middle button paste , or it was meant to be. It appears I used the keystroke paste instead and then just continued without checking. A dumb mistake but not critical because it’s the project that lead me to Django. But seeking any outside help at this point is counterproductive.

The tutorial may not be absolutely PEP8 compliant.

That is true. But PyCharm was showing an error when I used the Pythonic method. I’m sure there is a switch somewhere to turn it off but it isn’t critical currently.

I’m learning about the various apps to check and clean up the code from Stephen Lott’s Object-Oriented Python (second edition). I know I need do put as much of the program logic into classes vs the fundamental function method. I am not a programmer by trade or training. I just used Python to automate a number of system admin functions and other various operations but it was bare bones, top down with a function or two thrown in. A programmer friend of mine told me in '96 to use C and never learn basic. C was too low level for me to do anything quickly. And so much of example code at the time looked like utter garbage. I finally ran into Python in '98 and used it on and off through 2005. I had done some programming in Visual REXX on OS/2 as shareware. But that’s it. My two manuals on REXX where about 1/4 inch thick for each.

Back to topic, I will be sure to use Black. There are others mentioned in Chapter 1 but I have to get further in before learning more about it in practice. When my project gets to the point where I’ll be seeking volunteers, they may get a laugh at my madness, but I’m not going to be embarrassed by actual code. The strict formatting that PEP 8 calls for is the very reason I settled on Python. You could still write ugly code, but it made it simpler to read the logic and methods vs C.

I appreciate your time. Thank you much.
Doug

I strongly disagree with this statement, but you’ll find people on both sides of the argument :slight_smile:

Check out Django Views — The Right Way for a guide on using function-based views in Django.

Interesting! Good to know that code standards attract people to the language.

re: I know I need do put as much of the program logic into classes

I strongly disagree with this statement, but you’ll find people on both sides of the argument.

Perhaps I misspoke in this particular circumstance since the docs emphasize performing all the heavy work in the views.py behind the scenes and not in the template. That’s what I was planning to do. The other reason is both performance and DRY. ie: minimize file I/O and use the tools available.

It doesn’t hurt that I’m extremely lazy either.

Interesting! Good to know that code standards attract people to the language.

I fell in love with Python at first sight. But it wasn’t the code standards per se, it was the formatting requirement. Readable code! (most of the time) with every feature I’d ever need. A philosophy I could get behind. But it’s a ‘scripting’ language came the response of the ‘real’ programmers at the time. The hardware now makes that a complete non-sequitur.

Thank you for your feedback. Much appreciated.

Doug

I am facing the same issue right now. Double, triple checked typos, still cannot find where the error is coming from. You told @dougglenn to correct variable name from question_id from question.id in polls/detail.html file.
I have wrote correct code with right variable name already.
Here is my code for reference: (actually same as above)

polls/detail.html

<form action="{% url 'polls:vote' question.id %}" method="post"> # This is where browser showing error
{% csrf_token %}
    <fieldset>
        <legend><h1>{{ question.question_text }}</h1></legend>
        {% if error_message %} <p><strong>{{ error_message }}</strong></p> {% endif %}
        {% for choice in question.choice_set.all %}
            <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
            <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
        {% endfor %}
    </fieldset>
    <input type="submit" value="Vote">
</form>

And here is my polls/urls.py:

from django.urls import path

from . import views

app_name="polls"

urlpatterns = [
    # e.g.: /polls/
    path('', views.IndexView.as_view(), name='index'),
    # e.g.: /polls/3/mysite/polls/urls.py
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    # e.g.: /polls/3/results/
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    # e.g.: /polls/3/vote/
    path('<int:question_id/vote/', views.vote, name='vote'),
]

I am this close from tearing my hairs outta head.

I think this is where your mistake lies:

    path('<int:question_id/vote/', views.vote, name='vote'),

You missed the closing > on the URL parameter. Add it like so:

    path('<int:question_id>/vote/', views.vote, name='vote'),

Did what you suggested, yet no success…
Actually, this was working properly before I came across Generic view: Less code is better section. Did everything which is told in that section. Even followed this thread.

@sandeshpd did you manage to get it working? If not, I think it would be best you open a new thread - feel free to @ me there. It seems like you’re facing a different but similar issue.

@sandeshpd Check your model name is it Question or Questions, by default DetailView creates variable based on model name ,you can override using context_object_name = “question” in DetailView and ResultView

1 Like

Sorry for late reply. It actually did not work out, but it’s okay cuz I was just trying out Django and following steps told in documentation. This thread can be closed now. Do you do it or I do it? I quite do not know about that.
Thanks a lot btw for taking your time and helping me out. :smiley: