Need help fixing a Django 404 error, not finding a static page using URLConf
My Django project is a single-application website where the homepage shows articles/posts from my database, and will have pages for tag topics and year/month archives. All other pages are static pages for photo and video galleries, and an about page — they don't use the database at all.
I'm trying to get one of the static pages to display, but I keep running into a 404 error with the following (note: I replaced the application's name with "<app_name>"):
No article found matching the query
Request Method: GET
Request URL: http://127.0.0.1:8000/illustrations
Raised by: <app_name>.views.ArticleDetailView
Using the URLconf defined in website.urls, Django tried these URL patterns, in this order:
admin
[name='home']
<slug:slug> [name='article_detail']
The current path, illustrations, matched the last one.
The homepage shows all articles in ListView, and you can click individual articles to view them in DetailView with the designated slug as the URL. The "illustrations" file is a separate static HTML page I'll use that has nothing to do with the database or either of the List or Detail views.
I can't tell if I should make the homepage a separate app, or if I just need to change my URLs/Views files. (I'm learning Django and Python, so I'm definitely learning as I go along here.)
Here's views.py:
from django.shortcuts import render
from django.views import generic
from .models import Article
from django.http import JsonResponse # Ignore for now, I just put this here for when I work on making a JSON feed
class ArticleListView(generic.ListView):
model = Article
paginate_by = 6
template_name = "index.html"
class ArticleDetailView(generic.DetailView):
model = Article
template_name = "article.html"
def illustrations(request):
return render(request, "illustrations.html")
urls.py (project):
from django.contrib import admin
from django.conf import settings
from django.urls import path, include
from django.conf.urls.static import static
urlpatterns = [
path('admin', admin.site.urls),
path("", include("<app_name>.urls")),
]
if settings.DEBUG: # new
urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urls.py (app):
from django.urls import path
from . import views
from django.conf.urls.static import static # Not sure if needed
from django.views.generic import TemplateView
from .views import ArticleListView, ArticleDetailView
# For setup info, see https://learndjango.com/tutorials/django-file-and-image-uploads-tutorial
urlpatterns = [
path("", ArticleListView.as_view(), name="home"), # This is index.html,
path("<slug:slug>", ArticleDetailView.as_view(), name="article_detail"),
path("illustrations", views.illustrations, name="illustrations"),
]
It's because Django doesn't know that "illustrations" isn't a slug for your model. slug
type will match any alphanumeric character, hyphen, or underscore (regex [A-Za-z0-9-_]
.
Django always proceeds with the first url pattern that matches, so it never reaches your intended url for "illustrations".
Options to fix:
1. Move "illustrations" url pattern above ArticleDetailView
# <app>.urls.py
urlpatterns = [
path("", ArticleListView.as_view(), name="home"), # This is index.html,
path("illustrations", views.illustrations, name="illustrations"),
path("<slug:slug>", ArticleDetailView.as_view(), name="article_detail"),
]
-Note: You could also most illustrations
to your project.urls
since that gets evald first.
2. Prefix the DetailView url so that "illustrations" doesn't match
# <app>.urls.py
urlpatterns = [
path("", ArticleListView.as_view(), name="home"), # This is index.html,
path("articles/<slug:slug>", ArticleDetailView.as_view(), name="article_detail"),
path("illustrations", views.illustrations, name="illustrations"),
]
Note:
The second method gets you closer to a more "traditional" URL/API naming scheme. Would suggest you also change ListView to "/articles/". This isn't an issue when you've only got one app, but once you add another (like "editorials" or something), it's easy to duplicate the URL scheme with "/editorials/" and "/editorials/".
Protip:
Check out django-debug-toolbar if you run into more issues with templates/views/urls etc. <5 minutes to set up and gives WAY more useful debug info than vanilla django.
More Tips:
If adding the "app" prefix the urls, do it in the project.urls
file where you import the .urls file (then you can keep your existing name structure in /urls b/c every url will have "your_app/" prefixed to the url.
You don't have to split the url file, especially with one app. It's not wrong or anything, but can make it easier to find things when all urls are together.