Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Python

Craig Dickson
Craig Dickson
22,666 Points

Unable to get all my views

Been trying to apply the stuff Kenneth went over in the Django Basics classes but i seem to be hitting a problem. Nation list goes to a page that lists the nations of interest, nation detail lists all the leagues in each nation and league detail is supposed to list each league separately but i only get the first league in the first nation, not sure why. Any help will be greatly appreciated.

Below is my code for my views.

def nation_list(request):
    nations = Nation.objects.all()
    return render(request, 'soccer/nation_list.html', {'nations': nations})

def nation_detail(request, pk):
    nation = get_object_or_404(Nation, pk=pk)
    return render(request, 'soccer/nation_detail.html', {'nation': nation})

def league_detail(request, nation_pk, league_pk):
    league = get_object_or_404(League, nation_id=nation_pk, pk=league_pk)
    return render(request, 'soccer/league_detail.html', {'league': league})
Code for urls is below:

urlpatterns = [
    url(r'^$', views.nation_list),
    url(r'(?P<nation_pk>\d+)/(?P<league_pk>\d+)$', views.league_detail),
    url(r'(?P<pk>\d+)/$', views.nation_detail), 
]
Below is my league detail html code:

{% extends "layout.html" %}

{% block title %}{{ league.title }} - {{ league.nation.country_name }}{% endblock %}

{% block content %}
<article>
    <h2>{{ league.nation.country_name }}</h2>
    <h3>{{ league.title }}</h3>
    {{ league.content|linebreaks }}
</article>
{% endblock %}

Here is what i have for my models.py:

class Nation(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    country_name = models.CharField(max_length=255)
    description = models.TextField()

    def __str__(self):
        return self.country_name

class League(models.Model):
    title = models.CharField(max_length=255)
    description = models.TextField()
    order = models.IntegerField(default=0)
    nation = models.ForeignKey(Nation)

    class Meta:
        ordering = ['order',]

    def __str__(self):
        return self.title
Chris Freeman
Chris Freeman
Treehouse Moderator 68,227 Points

In your nation_detail and league_detail you are only asking and getting a single object using the get_object_or_404. When this single object is passed to the template it needs to be expanded by looping over the associated models.

Can you post your models.py?

Craig Dickson
Craig Dickson
22,666 Points

Chris, i have added my models.py bit. Thanks for the help.

1 Answer

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,227 Points

Hi Craig, here is what I observe.

  • each League points to a single Nation through the ForeignKey
  • a Nation can have many Leagues pointing at it. This can be seen in the nation.league_set queryset.
  • the league_detail gets a single league based on a unique league_pk and nation_id and passes it to the template for display. Only on nation is asked for and is displayed
  • to see the details of another league, a different URL needs to be provided.

I created mock data for nations and leagues. The follow data is shown with the URL to access them

League title, id, nation, nat_id
title:USL, leg_id:1, nation:U.S., nat_id:1  # league detail at URL /1/1
title:USL2, leg_id:4, nation:U.S., nat_id:1  # league detail at URL /1/2
title:USL3, leg_id:5, nation:U.S., nat_id:1  # league detail at URL /1/3
title:UKL, leg_id:2, nation:U.K., nat_id:2  # league detail at URL /2/2
title:CL, leg_id:3, nation:Can., nat_id:3  # league detail at URL /3/3

Re-reading your question, is the issue that you can only see one league_detail view and no other? Or is it that you wish the league_detail to also list all of the Leagues that happen to have the same Nation as the currently viewed League?

Craig Dickson
Craig Dickson
22,666 Points

Hi Chris,

Your observations are right. I have certain nations with multiple leagues and want to view the leagues in the nations. Using the mock data you listed, i want to move from URL /1/1 to URL /1/2 and so forth but i only get URL /1/1 and when i try to get URL /1/2 (different league in the same nation) i get a 404. Not sure why, i am following on with what Kenneth did in the Django Basics course.

Chris Freeman
Chris Freeman
Treehouse Moderator 68,227 Points

Correct. There is no "URL /1/2". There is a typo in my comment URLs (done by hand). Recreating using script in django shell (python manage.py shell):

>>> for leg in League.objects.all():
...     print("pk:{0}, title:{1}, nation:{2}(id:{3}) # URL: /{3}/{0}".format(leg.pk, leg.title, leg.nation.country_name, leg.nation.id))
... 
pk:1, title:USL, nation:U.S.(id:1) # URL: /1/1
pk:4, title:USL2, nation:U.S.(id:1) # URL: /1/4
pk:5, title:USL3, nation:U.S.(id:1) # URL: /1/5
pk:2, title:UKL, nation:U.K.(id:2) # URL: /2/2
pk:3, title:CL, nation:Can.(id:3) # URL: /3/3

While convenient for coding, get_object_or_404 isn't helpful on debug. For debug, try changing your league_detail view to:

def league_detail(request, nation_pk, league_pk):
    # league = get_object_or_404(League, nation_id=nation_pk, pk=league_pk)
    try:
        league = League.objects.get(nation_id=nation_pk, pk=league_pk)
    except League.DoesNotExit:
        # DEBUG:
        # try to get league without nation
        try:
            leg = League.objects.get(pk=league_pk)
        except League.DoesNotExit:
            string = "Sorry League {} Does Not Exist".format(leg.league_pk)
            return string
        else:
            # league exists, but not with this nation
            string = ("Sorry League {}(id:{}) exists but has Nation {}(id:{}), not {}"
                      "".format(leg.title, leg.pk, leg.nation.country_name,
                                leg.nation.pk., nation_pk))
            return string

    return render(request, 'soccer/league_detail.html', {'league': league})