Django Hello, World 5 Different Ways

Django is a "batteries-included" framework that comes with built-in scaffolding provided by the startproject command and the general concepts of apps. But, actually, Django provides incredible flexibility if desired around structure.

Consider how to architect a single page website: what's the simplest way to do it? Off the top of my head, at least 5 approaches come to mind. Because if you really think about it, apps are not mandatory at all but rather an organizational convenience that help reason about the codebase. Ditto for independent views files. We don't even need templates for a simple site when we can return strings in a view. Pretty much a urls.py file is the only "mandatory" part of the exercise.

Setup

On your command line, create a new directory called five and make a new Django project. We'll be using Pipenv here and calling our top-level directory config.

$ pipenv install django~=3.1.0
$ pipenv shell
(five) $ django-admin startproject config .
(five) $ python manage.py migrate
(five) $ python manage.py runserver

Navigate over to the Django homepage at http://127.0.0.1:8000/ to confirm everything is working.

Django welcome page

1. App + TemplateView

The "traditional" approach would be to create a dedicated app for static pages and use TemplateView, a generic class-based view provided by Django.

First, create the app which can be called whatever we choose. In this case, it'll be pages. Make sure you've stopped the local server by typing Control+c.

(five) $ python manage.py startapp pages

Add the new app to our INSTALLED_APPS setting.

# config/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'pages', # new
]

Update the config/urls.py file by importing include and adding a path for the pages app.

# config/urls.py
from django.contrib import admin
from django.urls import path, include # new

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('pages.urls')), # new
]

Ok, now what? We need a urls.py file within our app, a views file, and a template file.

Let's start with the pages/urls.py file. First, create it by using the touch command if you're on a Mac.

(five) $ touch pages/urls.py

The code includes a single path at home1/, a HomePageView we haven't created yet, and the URL name of home.

# pages/urls.py
from django.urls import path

from .views import HomePageView

urlpatterns = [
    path('home1/', HomePageView.as_view(), name='home1'),
]

The view imports TemplateView and points to a template called home.html.

# pages/views.py
from django.views.generic import TemplateView


class HomePageView(TemplateView):
    template_name = 'pages/home.html'

And finally we need a template. Create a templates directory within the pages app, then a new directory called pages, and finally the template called home.html.

<!- pages/templates/pages/home.html ->
<h1>Hello World</h1>

Start up the local server again with python manage.py runserver and navigate to http://127.0.0.1:8000/home1/.

1st Homepage

This approach works well for large projects where you want a dedicated pages app for static pages. But since this article is for educational purposes, let's see 4 more ways we can achieve the same outcome.

2. Function-Based View

The first thing we could do is swap out the generic class-based TemplateView for a function-based view. Django allows for either using function-based or class-based views.

We'll import render at the top of pages/views.py and add a new view, home_page_view2, which requests the same template home.html.

# pages/views.py
from django.shortcuts import render # new
from django.views.generic import TemplateView


class HomePageView(TemplateView):
    template_name = 'pages/home.html'


def home_page_view2(request): # new
    return render(request, 'pages/home.html')

This new view will have its own path, home2/, in the pages/urls.py file.

# pages/urls.py
from django.urls import path

from .views import HomePageView, home_page_view2 # new

urlpatterns = [
    path('home1/', HomePageView.as_view(), name='home1'),
    path('home2/', home_page_view2, name='home2'), # new
]

Make sure the server is still running and navigate to http://127.0.0.1:8000/home2/ to see the new version of our homepage in action.

2nd Homepage

3. No Template!

A third approach would be to remove the template entirely, since all we're displaying is a short amount of text. We can create a new view that does this by importing HttpResponse and hard-coding the string Hello World to be returned.

# pages/views.py
from django.shortcuts import render, HttpResponse # new
from django.views.generic import TemplateView


class HomePageView(TemplateView):
    template_name = 'pages/home.html'


def home_page_view2(request): 
    return render(request, 'pages/home.html')


def home_page_view3(request): # new
    return HttpResponse('Hello World')
# pages/urls.py
from django.urls import path

from .views import HomePageView, home_page_view2, home_page_view3 # new

urlpatterns = [
    path('home1/', HomePageView.as_view(), name='home1'),
    path('home2/', home_page_view2, name='home2'),
    path('home3/', home_page_view3, name='home3'), # new
]

Navigate to http://127.0.0.1:8000/home3/ in your web browser to see this third version in action.

3rd Homepage

4. No App!

We don't have to use apps, actually, if we don't want to. It's possible to create a "Hello World" page solely within our project-level config directory.

Here is all the code we need in just a single file:

# config/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView # new

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('pages.urls')),
    path('home4/', TemplateView.as_view(template_name='pages/home.html'), name='home4'), # new
]

We've imported TemplateView at the top, create a new URL path, pointed to the existed template within the path, and provided an updated URL name of home4.

Navigate to http://127.0.0.1:8000/home4/ to see this in action!

4th Homepage

5. Models

A fifth approach would be to use the database to display our "Hello World" message. That involves adding a models.py file and leveraging the built-in DetailView.

Create a new file called pages/models.py. We'll only add a single field, text, to the model called Post. Adding an optional __str__ method means the model will display nicely within the Django admin.

# pages/models.py
from django.db import models


class Post(models.Model):
    text = models.TextField()

    def __str__(self):
        return self.text[:50]

Since we made a change to our database models, it's time for a migrations file and then to invoke migrate to update the database.

(five) $ python manage.py makemigrations
(five) $ python manage.py migrate 

We'll want a basic pages/admin.py file to see our pages app within the admin so update pages/admin.py as follows:

# pages/admin.py
from django.contrib import admin

from .models import Post

admin.site.register(Post)

Create a superuser account and start up the server again.

(five) $ python manage.py createsuperuser
(five) $ python manage.py runserver

Log in to the admin at http://127.0.0.1:8000/admin/ and click on the link for Posts under Pages.

Admin

Click on "+Add" next to it. Add our text which will be "Hello World" and click the "Save" button in the bottom right.

Add Post

Success! We've added our first post to the database.

Admin post

To display this post we'll need a urls file, a views file, and a template file. Start with pages/urls.py where we'll import a new view called HomeDetailView and add a path for it.

# pages/urls.py
from django.urls import path

from .views import HomePageView, home_page_view2, home_page_view3, HomeDetailView # new

urlpatterns = [
    path('home1/', HomePageView.as_view(), name='home1'),
    path('home2/', home_page_view2, name='home2'),
    path('home3/', home_page_view3, name='home3'),
    path('home/<int:pk>/', HomeDetailView.as_view(), name='post_detail'), # new
]

The pages/views.py file needs to import DetailView at the top and our Post model. Then create HomeDetailView which references our Post model and a new pages/home5.html template.

# pages/views.py
from django.shortcuts import render, HttpResponse 
from django.views.generic import TemplateView, DetailView # new

from .models import Post # new

class HomePageView(TemplateView):
    template_name = 'pages/home.html'


def home_page_view2(request): 
    return render(request, 'pages/home.html')


def home_page_view3(request): 
    return HttpResponse('Hello, World!)


class HomeDetailView(DetailView): # new
    model = Post
    template_name = 'pages/home5.html'

The last step is to create a new template called home5.html that will display the text field from our model.

<!-- pages/templates/home5.html -->
{{ post.text }}

Make sure the local server is running python manage.py runserver and navigate to http://127.0.0.1:8000/home/1/ to see our 5th approach in action.

5th Homepage

And there it is!

Conclusion

If you understand these five approaches you'll be well on your way to understanding all that Django has to offer. And you can start exploring additional ways to tackle this arbitrary challenge, for example, taking a look at base view class, get_context_data, HTTPRequest and likely many others.