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 trial

Python Django Forms Model Forms Edit an Instance

TemplateSyntaxError and NoReverseMatch error

I'm getting multiple errors: 1) when I try to make a new quiz, I get: TemplateSyntaxError at /courses/1/create_quiz/ default requires 2 arguments, 1 provided --it tells me this line of the quiz_form template can't be rendered: {% block title %}{{ form.instance.title|default: "New Quiz" }} | {{ course.title }} {{ block.super }}{% endblock %} 5

2) If I try to edit a quiz, I get: NoReverseMatch at /courses/1/q6/ Reverse for 'edit_quiz' with arguments '()' and keyword arguments '{'course_pk': 1, 'quiz_pk': 6}' not found. 1 pattern(s) tried: ['courses/(?P<course_pk>\d+)/edit_quiz/(?P<step_pk>\d+)/$'] --It has a problem with the quiz detail: <a href="{% url 'courses:edit_quiz' course_pk=step.course.pk quiz_pk=step.pk %}" class="button"> 21
I have looked over my code two dozen times and I can't seem to figure out why this is happening.

Models:

class Step(models.Model):
    title = models.CharField(max_length=255)
    description = models.TextField() 
    order = models.IntegerField(default=0)
    course = models.ForeignKey(Course)

    class Meta:
        abstract = True
        ordering = ['order',]

    def __str__(self):
        return self.title

class Text(Step):
    content = models.TextField(blank=True, default='')

    def get_absolute_url(self):
        return reverse('courses:text', kwargs= {
            'course_pk': self.course_id,
            'step_pk':self.id
        })

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

Views:

def course_list(request):
    courses = models.Course.objects.all()
    return render(request, 'courses/course_list.html', {'courses': courses})


def course_detail(request, pk):
    course = get_object_or_404(models.Course, pk=pk)
    # chain() takes all the arguments and sorts it based on the key
    steps = sorted(chain(course.text_set.all(), course.quiz_set.all()),
            key=lambda step:step.order) #lambda is an unnamed function

    context = {
        'course':course,
        'steps': steps
    }
    return render(request, 'courses/course_detail.html', context)


def text_detail(request, course_pk, step_pk):
    step = get_object_or_404(models.Text, course_id=course_pk, pk=step_pk)
    return render(request, 'courses/text_detail.html', {'step': step})


def quiz_detail(request, course_pk, step_pk):
    step = get_object_or_404(models.Quiz, course_id=course_pk, pk=step_pk)
    return render(request, 'courses/quiz_detail.html', {'step': step})

@login_required
def quiz_create(request, course_pk):
    course = get_object_or_404(models.Course, pk=course_pk)
    form = forms.QuizForm()

    if request.method == 'POST':
        form = forms.QuizForm(request.POST)
        if form.is_valid():
            quiz = form.save(commit=False) # don't put in the database, just make the model instance
            # modify some stuff first
            quiz.course = course
            quiz.save()
            messages.add_message(request, messages.SUCCESS,
            "Quiz_added")
            return HttpResponseRedirect(quiz.get_absolute_url())

    context = {
        'form': form,
        'course':course
    }
    return render(request, 'courses/quiz_form.html', context)

@login_required
def quiz_edit(request, course_pk, quiz_pk = None):
    previously_created_quiz = get_object_or_404(models.Quiz, pk=quiz_pk,course_id=course_pk)
    form = forms.QuizForm(instance=previously_created_quiz) #tell django to start from previous quiz

    if request.method == 'POST':
        form = forms.QuizForm(instance=quiz, data=request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Updated {}".format(form.cleaned_data['title']))
            return HttpResponseRedirect(quiz.get_absolute_url())


    context = {
        'form': form,
        'course': previously_created_quiz.course
    }
    return render(request, 'courses/quiz_form.html', context)

Quiz form:

{% extends "courses/layout.html" %}


{% block title %}{{ form.instance.title|default: "New Quiz" }} | {{ course.title }} {{ block.super }}{% endblock %}


{% block breadcrumbs %}
    <li><a href="{% url 'courses:detail' pk=course.pk %}">{{ course.title }}</a></li>
{% endblock %}


{% block content %}
    <div class="row columns">
        {{ block.super }}
        <h1>{{ form.instance.title|default: "Make a New Quiz" }}Make a new quiz</h1>
        <form method="POST" action="">
            {% csrf_token %}
            {{ form.as_p }}
            <input type="submit" class="button" value="Save">
        </form>

    </div>
    {% endblock %}

quiz_detail.html:

{% block content %}
    <div class="row columns">

        <article>
            {{ block.super }} -->
            <h1>{{ step.title }}</h1>
            <p>Quiz questions here</p>
        </article>
        {% if user.is_authenticated %}
        <hr>
        <a href="{% url 'courses:edit_quiz' course_pk=step.course.pk quiz_pk=step.pk %}" class="button">
            Edit</a> 
            {% endif %}
    </div>
{% endblock %}

3 Answers

Ok try putting this

{% extends "courses/layout.html" %} {% load course %}

in quiz_detail.html that's what the video shows

and make sure there are no spaces between

<a href="{% url 'courses:edit_quiz' course_pk=step.course.pk quiz_pk=step.pk %}" class="button">Edit</a>

and let me know what that does for ya

For the second part try {% block title %}{{ form.instance.title|default: "New Quiz" }} | {{ course.title }} {{ block.super }}{% endblock %} putting together {{ form.instance.title|default:"New Quiz" }}

then <h1>{{ form.instance.title|default: "Make a New Quiz" }}Make a new quiz</h1> take out Make a new quiz and put toghter {{ form.instance.title|default:"Make a New Quiz" }} so it should look like this <h1>{{ form.instance.title|default:"Make a New Quiz" }}</h1> let me know what that does for ya

Thanks for your suggestions. Adding {% extends "courses/layout.html" %} {% load course %} in quiz_detail.html only resulted in an error saying that 'course' is not a tag. But I already have the {% load course_extras %}, so many that's what you meant?

Changing <h1>{{ form.instance.title|default: "Make a New Quiz" }}Make a new quiz</h1> to <h1>{{ form.instance.title|default:"Make a New Quiz" }}</h1> made a difference, so now I can make a new quiz.

However, after I submit a new quiz, I still get the 2nd error I originally posted--------- NoReverseMatch at /courses/1/q6/ Reverse for 'edit_quiz' with arguments '()' and keyword arguments '{'course_pk': 1, 'quiz_pk': 6}' not found. 1 pattern(s) tried: ['courses/(?P<course_pk>\d+)/edit_quiz/(?P<step_pk>\d+)/$'].

Ok I'm gonna have to pass you to someone else I'm not going to be on for a while My grandmother is in the hospital and she's not doing so good Hey Chris Freeman please help her out

Thanks for your help and best wishes for your grandmother!