Why am I getting a No Reverse Match Error

Viewed 72

HI working on a new site using Django. can't seem to figure this bug out. First the intended site will be structured as;

Home page - Showing different languages with links to countries you can learn those languages in. Click on a country on home page -> Country page Country page will list all fo the schools that teach that language in that country. Click on a school on country page -> School page.

I figured out this line of code in the Country page is causing the issue, but I don't know how to fix it

<a href="{% url 'schools' schools.id %}">
    <div class="left"><h4>Test Link</h4></div>
</a>

This is the error I get in the browser

NoReverseMatch at /5/ Reverse for 'schools' with arguments '('',)' not found. 1 pattern(s) tried: ['(?P<country_id>[0-9]+)/(?P<schools_id>[0-9]+)/$']

Code from the project: Models.py

from django.db import models

class Languages(models.Model):
    language = models.CharField(max_length=100, blank=True, null=True)
    country = models.ManyToManyField('Country', blank=True)
    image = models.CharField(max_length=100, blank=True)

    def __str__(self):
        return self.language

class Country(models.Model):
    country_name = models.CharField(max_length=50)
    country_image = models.CharField(max_length=100, blank=True)
    country_city = models.ManyToManyField('City', blank=True)

    def __str__(self):
        return self.country_name

class City(models.Model):
    city_name = models.CharField(max_length=50)
    city_image = models.CharField(max_length=1000, blank=True)
    city_schools_in = models.ManyToManyField('Schools', blank=True)

    def __str__(self):
        return self.city_name

class Schools(models.Model):
    school_name = models.CharField(max_length=100)
    school_image = models.CharField(max_length=1000, blank=True)
    school_country = models.ManyToManyField('Country', blank=True)
    school_city = models.ManyToManyField('City', blank=True)
    school_description = models.TextField()
    school_accreditations = models.ManyToManyField('Accreditations', blank=True)
    school_lpw = models.IntegerField()
    school_cs = models.IntegerField()
    school_course = models.ManyToManyField('CoursePrices', blank=True)

    def __str__(self):
        return self.school_name

class Accreditations(models.Model):
    accreditation_name = models.CharField(max_length=50)

    def __str__(self):
        return self.accreditation_name

class CoursePrices(models.Model):
    course_title = models.CharField(max_length=50, blank=True)
    lessons_per_week = models.IntegerField()
    class_size = models.IntegerField()
    weekly_price =  models.IntegerField()
    language_level = models.CharField(max_length=50, blank=True)

    def __str__(self):
        return self.course_title

Views.py

from django.shortcuts import render
from django.http import Http404

from .models import Schools, CoursePrices, Languages, Country, City


def home(request):
    languages = Languages.objects.all()
    return render(request, 'home.html', {
        'languages': languages,
    })

def country(request, country_id):
    try:
        country = Country.objects.get(id=country_id)
    except Languages.DoesNotExist:
        raise Http404('Language not found')
    return render(request, 'country.html', {
        'country': country,
    })

def schools(request, country_id, schools_id):
    try:
        schools = Schools.objects.get(id=schools_id)
    except Schools.DoesNotExist:
        raise Http404('school not found')
    return render(request, 'schools.html', {
        'schools': schools,
    })

urls.py

from django.contrib import admin
from django.urls import path

from schools import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.home, name='home'),
    path('<int:country_id>/', views.country, name='country'),
    path('<int:country_id>/<int:schools_id>/', views.schools, name='schools'),
]

Project structure screenshot

Project structure screenshot

Any help would be greatly appreciated. Also please forgive any mistakes in posting or coding, still very new to coding and stack overflow / life in general :)

2 Answers

Your path named schools requires two arguments, you only passed one, so it failed to match any route.

Your comment on Rafael's answer that it is still not matching the path, even with two arguments provided, is because of the order of the paths in your urls.py file.

Django will go through the list of paths in order, and because a path with the single parameter country_id is found first it tries that but fails because you have a second parameter.

To fix that change the order of your paths

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.home, name='home'),
    # next two lines have been swapped. 
    path('<int:country_id>/<int:schools_id>/', views.schools, name='schools'),
    path('<int:country_id>/', views.country, name='country'),
]

The 'schools' url needs two (2) arguments. You only pass one (1). In this case: schools.id

Django only finds a reverse match if you pass the correct amount of arguments. In this case, you should pass a country id AND a school id.

E.g. {% url 'schools' country_id=country.id schools_id=schools.id %} if you also have a country variable.

EDIT: '('',)' in your error message don't really look like integers. Are you sure the template variables exists and are integers?

Related