Django "Hello, World" 5 Different Ways
Tags: django, python, tutorial, beginners
Published: 2020-06-12 14:23:12

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.0.7
$ 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/](http://127.0.0.1:8000/) to confirm everything is working.

![Django Welcome Page](https://dev-to-uploads.s3.amazonaws.com/i/d7rdgl0c23okxkc30jji.png)

## 1. App + TemplateView

The "traditional" approach would be to create a dedicated app for static pages and use [TemplateView](https://docs.djangoproject.com/en/3.0/ref/class-based-views/base/#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.

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

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

```python 
# 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`.

```python 
# 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`.

```python 
# 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`.

```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/](http://127.0.0.1:8000/home1/).

![1st Homepage](https://dev-to-uploads.s3.amazonaws.com/i/nawurr9xjsgoobf9lcoh.png)

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`.

```python
# 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.

```python
# 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/](http://127.0.0.1:8000/home2/) to see the new version of our homepage in action.

![2nd Homepage](https://dev-to-uploads.s3.amazonaws.com/i/v95nlszqswb4ret9l8vm.png)

## 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.

```python
# 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')
```

```python
# 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/](http://127.0.0.1:8000/home3/) in your web browser to see this third version in action.

![3rd Homepage](https://dev-to-uploads.s3.amazonaws.com/i/nztlykqfb93htp5joxdl.png)

## 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:

```python 
# 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/](http://127.0.0.1:8000/home4/) to see this in action!

![4th Homepage](https://dev-to-uploads.s3.amazonaws.com/i/7b8u5rlpfcz3nk6lv4gh.png)

## 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](https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-display/#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.

```python 
# 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:

```python
# 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/](http://127.0.0.1:8000/admin/) and click on the link for `Posts` under `Pages`.

![Admin](https://dev-to-uploads.s3.amazonaws.com/i/vtq7ya1tehnzr9i5ys7z.png)

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

![Add](https://dev-to-uploads.s3.amazonaws.com/i/tyfcu3o77ri0c7l5fisb.png)

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

![Admin Post](https://dev-to-uploads.s3.amazonaws.com/i/gj5wugmhzfo5zz17gayt.png)

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.

```python
# 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.

```python
# 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.

```html
<!-- 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/](http://127.0.0.1:8000/home/1/) to see our 5th approach in action.

![5th Homepage](https://dev-to-uploads.s3.amazonaws.com/i/y0qgly015bsr0luogsi5.png)

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](https://docs.djangoproject.com/en/3.0/ref/class-based-views/base/#view), [get_context_data](https://docs.djangoproject.com/en/3.0/topics/class-based-views/generic-display/#adding-extra-context),  [HTTPRequest](https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest) and likely many others.