From “Not Found” to Live: Connecting Your Django Pages on Heroku (Part 4)

From “Not Found” to Live: Connecting Your Django Pages on Heroku (Part 4)

In the previous parts of this series, you successfully deployed your Django application to Heroku. You’ve configured your environment, pushed your code, and can access the Django admin interface at yourapp.herokuapp.com/admin. However, visiting your main URL likely presents you with a discouraging “Not Found” page. This is a common and expected step in the process. Your app is running, but you haven’t told Django what to show at the root URL or any other custom paths.

This guide, Part 4, will walk you through the final steps to bring your website to life. We will create the necessary views, templates, and URL patterns to display a homepage, a blog page, an about page, and a contact page. By the end, you’ll have a functional, multi-page website accessible to anyone on the internet.

Why Do I See a “Not Found” Error?

The “Not Found” error appears because Django’s URL dispatcher, defined in your urls.py file, doesn’t have an entry for the root path (/). Out of the box, a new Django project only defines the path for the /admin/ site. When a user visits your main domain, Django looks for a matching URL pattern, finds nothing, and returns a 404 error.

Our mission is to create these URL patterns and connect them to views that render HTML pages. We’ll build out a few essential pages to transform your project into a proper website.

Step 1: Create a ‘main’ App for Core Pages

It’s a Django best practice to organize different functionalities into separate apps. While you might have a blog app for your posts, general pages like the homepage, about, and contact sections fit well into a dedicated main or core app.

In your Cloud9 terminal, within your project’s root directory (where manage.py is located), create a new app:

python manage.py startapp main

Now, register this new app with your project. Open your settings.py file and add 'main' to the INSTALLED_APPS list:

# settings.py

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'main', # Add your new app here
# ... any other apps you have
]

Setting up Dual Database Configuration (Local & Production)

To ensure your project works seamlessly both locally and in production (such as Heroku), you’ll want to configure Django to use SQLite by default for local development, and switch automatically to a cloud database when the DATABASE_URL environment variable is detected.

Open your settings.py and update your database settings as follows:

# settings.py

import os
import dj_database_url

DATABASE_URL = os.environ.get('DATABASE_URL')

if DATABASE_URL:
# For production (Heroku), use the database specified in DATABASE_URL
DATABASES = {
'default': dj_database_url.config(default=DATABASE_URL)
}
else:
# For local development, default to SQLite
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}

Note: Make sure you have the dj-database-url package installed:

pip install dj-database-url

And add it to your requirements.txt:

pip freeze > requirements.txt

If you can not access the /admin/ site,

Summary Table

ProblemCauseFixed By
Bad Request (400)Wrong ALLOWED_HOSTS / CSRF_TRUSTED_ORIGINSWildcard settings (*.herokuapp.com, etc.)
500 error on /admin/login/Django refuses to serve admin static files–insecure –nostatic
Broken/missing CSScollectstatic copied files incorrectly–link flag (symlinks instead of copy)
Can’t access from Cloud9 preview

The Magic Local Development Command (Explained Piece by Piece)

Bash

python manage.py collectstatic --noinput --clear --link && \
python manage.py runserver --insecure --nostatic 0.0.0.0:8080

Let’s break it down:

Part 1: collectstatic –noinput –clear –link

Bash

python manage.py collectstatic --noinput --clear --link

This command copies all static files (CSS, JS, images) from your apps (including Django’s own admin app) into one folder that Django can serve.

FlagWhat it doesWhy we need it in Cloud9
–noinputSkips the “Are you sure?” promptSo the command runs without waiting for you to type yes
–clearDeletes the old staticfiles/ folder before collecting new filesPrevents old/broken files from lingering
–linkCreates symbolic links instead of copying filesThis is the real hero. Copying can break internal paths in Django’s admin files on Linux/Cloud9. Symlinks keep the original paths intact → styles load correctly

Without –link, you often get broken admin CSS even after collectstatic!

Part 2: runserver –insecure –nostatic 0.0.0.0:8080

Bash

python manage.py runserver --insecure --nostatic 0.0.0.0:8080
FlagWhat it doesWhy we need it in Django 4.2 + Cloud9
–insecureServes static files even when DEBUG=FalseWe usually run with DEBUG=True, but Django still sometimes refuses
–nostaticDisables the built-in static file warning/serving changes in Django 4.2+Django 4.2+ refuses to serve static files by default in some cases → 500 error
0.0.0.0:8080Makes the server accessible from outside the container (required for Cloud9 preview)Cloud9 can’t show 127.0.0.1:8000 — it needs port 8080 + 0.0.0.0

Important: Starting with Django 4.2, using just runserver is no longer enough for a perfectly styled admin in many environments. You must combine –insecure and –nostatic.

Testing Your Database Setup

  • Local Development:
    When you run your app locally with python manage.py runserver, Django will use SQLite by default. You can verify this in the Django shell:python manage.py shell
    >>> from django.conf import settings
    >>> settings.DATABASES
    # Output should show the SQLite configuration
  • Production (Heroku):
    On Heroku, after you add a database add-on (like Heroku Postgres), the DATABASE_URL will be set automatically in your app’s environment. Django will pick up this variable and use the cloud database. You can confirm this through the Heroku CLI:heroku config:get DATABASE_URL -a your-app-name

git add .
git commit -m “Allow local sql3 database for development”

git push heroku main

Step 2: Define the Views

Views are Python functions or classes that take a web request and return a web response. In our case, the response will be the HTML content of our pages.

Open the main/views.py file and add the following code. We’ll start by defining simple functions for our homepage, about page, and contact page.

# main/views.py

from django.shortcuts import render

def home(request):
"""
View for the homepage.
"""
return render(request, 'main/home.html')

def about(request):
"""
View for the about page.
"""
return render(request, 'main/about.html')

def contact(request):
"""
View for the contact page.
"""
return render(request, 'main/contact.html')

# We'll assume you have a separate 'blog' app for this view.
# If not, you can place this in 'main/views.py' for now.
# from django.shortcuts import render (already imported)

# def blog(request):
# """
# View for the blog listing page.
# """
# # In a real app, you would fetch blog posts from the database here
# # posts = Post.objects.all()
# # context = {'posts': posts}
# return render(request, 'blog/blog_list.html')

Each function uses Django’s render shortcut, which takes the request object and the path to an HTML template, then returns an HttpResponse object with that rendered template.

Step 3: Create the HTML Templates

Our views are now looking for HTML files that don’t exist yet. Let’s create them. Inside your main app directory, create a new folder named templates, and inside that, another folder named main.

Your directory structure should look like this:

main/
├── templates/
│ └── main/
│ ├── home.html
│ ├── about.html
│ └── contact.html
└── views.py
...

Now, create the HTML files with some basic content.

main/templates/main/home.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Welcome to My Website</title>
</head>
<body>
<h1>Homepage</h1>
<p>Welcome! Your Django site is now live on Heroku.</p>
</body>
</html>

main/templates/main/about.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>About Us</title>
</head>
<body>
<h1>About Page</h1>
<p>This is the page that tells visitors about you or your project.</p>
</body>
</html>

main/templates/main/contact.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Contact Us</title>
</head>
<body>
<h1>Contact Page</h1>
<p>Here's how to get in touch.</p>
</body>
</html>

Step 4: Connect the URLs

The final piece of the puzzle is to connect URLs to the views we created. This requires two steps: creating a urls.py for our main app and including it in the project’s main urls.py file.

First, create a new file named urls.py inside your main app directory.

main/urls.py:

from django.urls import path
from . import views

urlpatterns = [
path('', views.home, name='home'),
path('about/', views.about, name='about'),
path('contact/', views.contact, name='contact'),
]

This file defines the URL patterns for the main app. Notice the empty string '' for the homepage view.

Next, we need to tell our project-level URL configuration to look at this new file. Open your project’s urls.py file (the one in the same directory as settings.py).

myproject/urls.py:

from django.contrib import admin
from django.urls import path, include # Make sure 'include' is imported

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('main.urls')), # Include the URLs from the main app
# path('blog/', include('blog.urls')), # You would add this for your blog app
]

By using include('main.urls') with an empty path '', we are telling Django to send any request that matches the root (yourapp.herokuapp.com/) to the main/urls.py file for further processing. There, the empty path '' matches views.home, successfully routing the user to your homepage.

Step 5: Deploy the Changes

You’ve made significant changes to your codebase. It’s time to push them to Heroku so they become live.

Run the following commands in your terminal:

# Stage all your new and modified files
git add .

# Commit the changes with a descriptive message
git commit -m "Add main app with home, about, and contact pages"

# Push the changes to Heroku
git push heroku main

Heroku will automatically rebuild your application with the new code. Once the deployment is complete, navigate to https://yourapp.herokuapp.com/.

You should now see your “Homepage” content instead of the “Not Found” error! You can also test your other pages by visiting https://yourapp.herokuapp.com/about/ and https://yourapp.herokuapp.com/contact/.

Conclusion and Next Steps

Congratulations! You have successfully bridged the gap between a backend-only application and a functional website with live pages. By creating a dedicated app for your core pages, defining views, building templates, and mapping the URL patterns, you have established the fundamental structure of your Django site.

From here, you can continue to build out your site’s functionality:

  • Create a Base Template: Avoid repeating the <html>, <head>, and <body> structure on every page by using Django’s template inheritance.
  • Style Your Pages: Integrate CSS to make your site visually appealing. Remember to configure whitenoise to serve your static files.
  • Build Out the Blog: If you have a blog app, follow the same pattern to create views and templates for listing posts and viewing individual post details.

You’re no longer stuck at the admin login. Your project is now a real website on the internet, ready for you to share and build upon.

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *