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 Basics Test Time Django TDD

Nthulane Makgato
PLUS
Nthulane Makgato
Courses Plus Student 19,602 Points

Last error on TDD challenge doesn't pass

Hi guys, please help me with this challange. I have managed to pass all other tests except one the last one.

 def test_performer_detail_view(self):
        '''The performer_detail view should:
           * return a 200
           * have self.performer in the context
           * use the songs/performer_detail.html template
           * show the string version of self.song in the template
        '''
        resp = self.client.get(reverse('songs:performer',
                                       kwargs={'pk': self.performer.pk}))
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.context['performer'], self.performer)
        self.assertTemplateUsed(resp, 'songs/performer_detail.html')
        self.assertContains(resp, str(self.song))

And the error that i get is

NoReverseMatch: Reverse for 'detail' with arguments '()' and k_p':1}' not found . 
1 pattern (s) tried : ['songs/song/(?P<pk>\\d+)/$']

I don't really understand it. Your assistance would be greatly appreciated.

songs/models.py
from django.db import models

# Write your models here
class Performer(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Song(models.Model):
    title = models.CharField(max_length=255)
    artist = models.CharField(max_length=100)
    performer = models.ForeignKey(Performer, max_length=100)
    length = models.IntegerField()

    def __str__(self):
        return '{} by {}'.format(self.title,self.artist)
songs/views.py
from django.shortcuts import render, get_object_or_404

from .models import Performer, Song

def song_list(request):
    songs = Song.objects.all()
    return render(request, 'songs/song_list.html', {'songs':songs})

def song_detail(request, pk):
    song = get_object_or_404(Song, pk=pk)
    return render(request, 'songs/song_detail.html', {'song': song})

def performer_detail(request, pk):
    performer = get_object_or_404(Performer, pk=pk)
    return render(request, 'songs/performer_detail.html', {'performer':performer})
songs/templates/songs/performer_detail.html
{% extends 'base.html' %}

{% block title %}{{ performer }}{% endblock %}

{% block content %}
<h2>{{ performer.name }}</h2>
    {% for song in performer.song_set.all %}
        <a href="{% url 'songs:detail' performer_pk=performer.pk song_pk=song.pk %}">song.title</a>
    {%endfor %}

{% endblock %}

5 Answers

Ryan S
Ryan S
27,276 Points

Right, I forgot that the url patterns were already set up for you.

I think the error might be caused by your href attribute in the performer_detail template. The song_detail view is expecting a single "pk" argument, but you are attempting to supply two arguments to the url lookup. (I think that is why the double backslash showed up in the error regarding that url. It was expecting a pk of some kind in between them.)

The challenge only specifies that you need to list the songs of each performer, not necessarily provide a link to them.

You should be able to get by simply by listing the song as its __str__ method. Example:

{% extends 'base.html' %}

{% block title %}{{ performer }}{% endblock %}

{% block content %}
  <h2>{{ performer }}</h2>
  {% for song in performer.song_set.all %}
    {{ song }}
  {% endfor %}
{% endblock %}

If you want to include a link, then you only need to supply the song pk argument, i.e., pk = song.pk. Since you are already on the performer_detail page and accessing the song_set of that particular performer, it won't be necessary to use the performer pk.

Also, don't forget that to access variables in a template you need to wrap them in double curly braces {{ }}.

I haven't actually tried running your code at all so I'm trying to debug it by just looking at it. But hopefully this will get us somewhere.

Ryan S
Ryan S
27,276 Points

Hi Nthulane,

It might be helpful to post urls.py as well. But looking at your error I noticed that you have an extra backslash before the '\d+' characters.

['songs/song/(?P<pk>\\d+)/$']

#try removing the extra slash in song_detail url
'(?P<pk>\d+)/$'
Nthulane Makgato
PLUS
Nthulane Makgato
Courses Plus Student 19,602 Points

Hi Ryan!

Thanks for responding!

I don't think that that page matters because we don't change it but I understand why you'd want to see it.

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'performer/(?P<pk>\d+)/$', views.performer_detail, name='performer'),
    url(r'song/(?P<pk>\d+)/$', views.song_detail, name='detail'),
    url(r'', views.song_list, name='list'),
]

Looking forward to your response.

Nthulane Makgato
PLUS
Nthulane Makgato
Courses Plus Student 19,602 Points

You make some good points, especially the silly mistake with the missing {{ }}. I notice that i'm still a bit confused about the pk and when they should be used especially in template. I'll read up on them some.

Thanks for your response ;)

Ryan S
Ryan S
27,276 Points

No problem. Glad I could be of some help.

Yeah I had a hard time at first wrapping my head around all those pk's and how to use them, but as you go through the rest of the Django courses it'll start to make more sense.

Basically the url template tag does a reverse match to the urlpattern, and will build a string of that urlpattern. Normally, you'd enter a url in your browser, then Django would try to match it in the urlpatterns, find the view it needs to call and pull the argument out of the url string (if there is one) to be supplied to the view.

With the url template tag, you first specify the urlpattern that you want to build, and supply the arguments that both the view and the url need to be complete. Then it can be used to build a dynamic href string in your anchor tag. But everything needs to match. If there is a mismatch between the arguments required vs the ones supplied, then you will get a NoReverseMatch error as you did above, since the newly created url string won't match the pattern you specified.