Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialJonathan Mitten
Courses Plus Student 11,197 PointsReverse for 'quiz' with keyword arguments '{'course_pk': 1}' not found. 1 pattern(s) tried: ['courses/(?P<course_pk>\\d+
I see some folks who have run up against this issue in much earlier video chapters, and I've tried to follow the debug logic to the best of my ability. I'm just not able to solve this issue. I've even gone so far as to dig into the final version of the project (in the downloads section) and cross-referenced my templates, models, forms, views, and URLs, and the project has been working up to this chapter (https://teamtreehouse.com/library/django-forms/model-forms/handling-multiple-form-classes).
The big question is how can this error be debugged? It seems like a big question on StackOverflow. Here is my quiz_detail.html
template, which throws the error after a "New Multiple Choice Question" or "New True / False Question" button click, so the error actually occurs on the URL http://site_root/courses/2/create_question/mc/
(I'm running on my own dev server):
{% extends "courses/layout.html" %}
{% load course_extras %}
{% block title %}
{{ step.title }} | {{ step.course.title }} {{block.super }}
{% endblock title %}
{% block breadcrumbs %}
<li><a href="{% url 'courses:detail' pk=step.course.pk %}">{{ step.course.title }}</a></li>
{% endblock breadcrumbs %}
{% block content %}
<div class="row columns">
<article>
{{ block.super }}
<h1>{{ step.title }}</h1>
Quiz questions here
</article>
{% if user.is_authenticated %}
<hr />
<div>Debug: step.pk is: {{step.pk}} </div>
<a
href="{% url 'courses:edit_quiz' course_pk=step.course.pk quiz_pk=step.pk %}"
class="button">
Edit
</a>
<a
href="{% url 'courses:create_question' quiz_pk=step.pk question_type='mc' %}"
class="button">
New Multiple Choice Question
</a>
<a
href="{% url 'courses:create_question' quiz_pk=step.pk question_type='tf' %}"
class="button">
New True/False Question
</a>
{% else %}
<p>You're not auth'ed</p>
{% endif %}
<div>quiz_detail.html</div>
</div>
<!-- /.row columns -->
{% endblock content %}
The urls.py looks like this:
"""URLS."""
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.course_list, name='list'),
url(r'(?P<course_pk>\d+)/t(?P<step_pk>\d+)/$', views.text_detail,
name='text'),
url(r'(?P<course_pk>\d+)/q(?P<step_pk>\d+)/$', views.quiz_detail,
name='quiz'),
url(r'(?P<course_pk>\d+)/create_quiz/$', views.quiz_create,
name='create_quiz'),
url(r'(?P<course_pk>\d+)/edit_quiz/(?P<quiz_pk>\d+)/$', views.quiz_edit,
name='edit_quiz'),
url(r'(?P<quiz_pk>\d+)/create_question/(?P<question_type>mc|tf)/$',
views.create_question, name='create_question'),
url(r'(?P<pk>\d+)/$', views.course_detail, name='detail'),
]
and the view called by the create_question URL is here:
@login_required
def create_question(request, quiz_pk, question_type):
"""Create question."""
quiz = get_object_or_404(models.Quiz, pk=quiz_pk)
if question_type == 'tf':
form_class = forms.TrueFalseQuestionForm
else:
form_class = forms.MultipleChoiceQuestionForm
form = form_class()
if request.method == 'POST':
form = form_class(request.POST)
if form.is_valid():
question = form.save(commit=False)
question.quiz = quiz
question.save()
messages.success(request, "Added question")
return HttpResponseRedirect(quiz.get_absolute_url())
return render(request, 'courses/question_form.html', {
'quiz': quiz,
'form': form
})
and the models I believe are in the scope of this issue, here:
class Quiz(Step):
total_questions = models.IntegerField(default=4)
class Meta:
verbose_name_plural = 'Quizzes'
def get_absolute_url(self):
return reverse('courses:quiz', kwargs={
'course_pk': self.course_id,
'step_pk': self.id
})
class Question(models.Model):
quiz = models.ForeignKey(Quiz)
order = models.IntegerField(default=0)
prompt = models.TextField()
class Meta:
ordering = ['order',]
def get_absolute_url(self):
return self.quiz.get_absolute_url()
def __str__(self):
return self.prompt
class MultipleChoiceQuestion(Question):
shuffle_answers = models.BooleanField(default=False)
class TrueFalseQuestion(Question):
pass
Going through the traceback, the legible error message comes from:
Template error:
In template /path/to/learning_site/templates/layout.html, error at line 0
Reverse for 'quiz' with keyword arguments '{'course_pk': 1}' not found. 1 pattern(s) tried: ['courses/(?P<course_pk>\\d+)/q(?P<step_pk>\\d+)/$'] 1 : <!doctype html>
2 : {% load static from staticfiles %}
3 : {% load course_extras %}
4 : <html class="no-js" lang="en">
5 : <head>
6 : <meta charset="utf-8">
7 : <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 : <title>{% block title %}{% endblock %}</title>
9 : <link rel="stylesheet" href="{% static 'css/foundation.min.css' %}">
10 : <link rel="stylesheet" href="{% static 'css/layout.css' %}">
This all seems to match with the "Final" version provided by the download. I'm going to see if I can track down the changes by finding the chapter directory and going through to copy and paste, and if I find the answer, I'll post it here.
How can a developer debug the NoReverseMatch error, precisely?
1 Answer
Jonathan Mitten
Courses Plus Student 11,197 PointsI found the culprit, and it's not in the files or code I posted. It was in the question_form.html
and was buried in one of the breadcrumbs.
For those interested, the old file read:
{% extends "courses/layout.html" %}
{% load course_extras %}
{% block title %}
New question for {{quiz.title}} | {{ quiz.course.title }} {{block.super}}
{% endblock title %}
{% block breadcrumbs %}
<li><a href="{% url 'courses:detail' pk=quiz.course.pk %}">{{ quiz.course.title }}</a></li>
<li><a href="{% url 'courses:quiz' course_pk=quiz.course.pk %}">{{ quiz.title }}</a></li>
{% endblock breadcrumbs %}
{% block content %}
<div class="row columns">
{{ block.super }}
<h1>Make a new question</h1>
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="button" value="Save" />
</form>
</div>
<!-- /.row columns -->
{% endblock content %}
<div>question_form.html</div>
and the issue was in the second breadcrumb, where courses:quiz
is passing only the course_pk
argument to the URL. The step_pk
is of course also required. The file now reads:
{% extends "courses/layout.html" %}
{% load course_extras %}
{% block title %}
New question for {{quiz.title}} | {{ quiz.course.title }} {{block.super}}
{% endblock title %}
{% block breadcrumbs %}
<li><a href="{% url 'courses:detail' pk=quiz.course.pk %}">{{ quiz.course.title }}</a></li>
<li><a href="{% url 'courses:quiz' course_pk=quiz.course.pk step_pk=quiz.pk %}">{{ quiz.title }}</a></li>
{% endblock breadcrumbs %}
{% block content %}
<div class="row columns">
{{ block.super }}
<h1>Make a new question</h1>
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="button" value="Save" />
</form>
</div>
<!-- /.row columns -->
{% endblock content %}
<div>question_form.html</div>
and the form renders as expected.
It is spectacularly irritating that the file question_form.py
is not mentioned in any of the debug messaging, but I suppose the answer to my question of "how do we debug NoReverseMatch" is to search the project files for the term courses:quiz and check each line where it's included. In my case, it's the only file outside of the models.py
that has that url - I suppose that's the DRY method in action there, anyway.