Django
Hello App in Django

Hello App in Django

In this tutorial we will build, test and deploy a Hello app containing a homepage and about page. We will learn about class-based views and templates which are the building blocks for the more complex web application.

The following tutorial has been operated on Ubuntu 22.04.02 with the Python Version 3.10.6.

Table of Contents

Start a new Django Project

django-admin startproject django_app_project

Create an app named Hello_app

cd django_app_project
python3 manage.py startapp Hello_app

Open django_app_project/settings.py in your text editor and add the app.

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'Hello_app.apps.HelloAppConfig', #new
]
#Migrate
python3 manage.py migrate
python3 manage.py runserver

Templates

Every web framework needs a convenient way to generate HTML files and in Django the approach is to use templates: individual HTML files that can be linked together and also include basic logic.

There are two options when it comes to place templates within the structure of a Django project. By default, Django’s template loader will look within each app for related templates. However the structure is somewhat confusing: each app needs a new templates directory, another directory with the same name as the app, and then the template file.

This means we would need to create a new templates directory, a new directory with the name of the app, Hello_app and finally our template itself which is home.html.

The second approach is to create a single project-level templates directory and place all templates within there. By making a small tweak to our django_app_project/settings.py file we can tell Django to also look in this directory for templates.

Create directory named templates and add it with the following code.

#django_app_project/settings.py
TEMPLATES = [
{
"DIRS" : [BASE_DIR / "templates"] #new
}
]

Within the templates directory create a new file called home.html and add the following code.

<!DOCTYPE html>
<h1>Hompage</h1>

Class-Based Views

In our view we will use the built-in TemplateView to display our template. Update the Hello_app/views.py file.

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

#Capitalize name of class
class HomePageView(TemplateView):
    template_name = "home.html"

URLs

Edit django_app_project/urls.py file

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

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

Create a file named “urls.py” inside the “Hello_app” folder and fill it with following code.

#Hello_app/urls.py

from django.urls import path
from .views import HomePageView

urlpatterns = [
path("",HomePageView.as_view(),name="home")
]

The project Directory so Far

About Page

Create a new template file called templates/about.html and populate it with a short HTML headline.

<!DOCTYPE html>
<h1>About Page</h1>

Add a new view in Hello_app/views.py

class AboutPageView(TemplateView): 
    template_name = "about.html"

Finally import the view name and connect it to a URL at about/.

Edit Hello_app/urls.py as follows:

#Hello_app/urls.py
..................
from .views import HomePageView, AboutPageView

urlpatterns = [
path("about/",AboutPageView.as_view(),name="about"),
.....
]

Run server and visit http://127.0.0.1:8000/about

Extending Templates

The real power of templates is their ability to be extended. If you think about most websites, there is content that is repeated on every page (header, footer, etc).

Let us create a templates/base.html.

Django has a minimal templating language for adding links and basic logic in our templates. Template tags take the form of {% something %} where “something” is the template tag itself.

To add URL links in our project we can use the built-in url template tag which takes the URL pattern name as an argument.

Write the following code in templates/base.html

<!DOCTYPE html>
<header>
    <a href="{% url "home" %}">Home</a>
    <a href="{% url "about" %}">About</a>
</header>

{% block content %}
{% endblock content %}
<footer>
    <h2>This is footer</h2>
</footer>

At the bottom we have added a block tag called content. Blocks can be overwritten by child templates via inheritance. While it is optional to name our closing endblock, one can just write {% endblock%} if one prefers – doing so help with readability, especially in larger template files.

Now, we will update home.html and about.html files to extend the base.html template.

Edit templates/home.html as follow:

{% extends "base.html" %}

{% block content %}
<h1>Home Page</h1>
{% endblock content %}

Edit templates/about.html as follow:

{% extends "base.html" %}

{% block content %}
<h1>About</h1>
{% endblock content %}

Run again

Tests

It is important to add automated tests and run them whenever a codebase changes. Test require a small amount of upfront time to write but more than pay off later.

Django’s testing framework provides several extensions on the top of Python’s unittest.TestCase base class. These include a test client for making dummy Web browser requests, a number of Django-specific additional assertions, and four test classes: SimpleTestCase, TestCase, TransactionTestCase and LiveServerTestCase.

SimpleTestCase is used when a database is not necessary while TestCase is used when you do want to test the database. TransactionTestCase is useful if you need to directly test database transactions while LiveServerTestCase launches a live server thread useful for testing with browser-based tools like Selenium.

We will test two URLs for our website, the homepage and about page, both should return HTTP status code of 200, the standard response for a successful HTTP reuest.

Edit Hello_app/tests.py as follow

#Hello_app/tests.py
from django.test import TestCase
from django.test import SimpleTestCase

# Create your tests here.
class HomePageTexts(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get("/")
        self.assertEqual(response.status_code,200)

class AboutPageTests(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get("/about/")
        self.assertEqual(response.status_code,200)

Run the following command in the terminal.

python3 manage.py test

Django utility function reverse can be used to check name of “home” for the homepage path and “about” for the about page.

#Hello_app/tests.py
from django.test import TestCase
from django.test import SimpleTestCase
from django.urls import reverse #new

# Create your tests here.
class HomePageTexts(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get("/")
        self.assertEqual(response.status_code,200)

    #new
    def test_url_available_by_name(self):
        response = self.client.get(reverse("home"))
        self.assertEqual(response.status_code,200)

class AboutPageTests(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get("/about/")
        self.assertEqual(response.status_code,200)
    #new
    def test_url_available_by_name(self):
        response = self.client.get(reverse("about"))
        self.assertEqual(response.status_code,200)

Let us make sure that the correct templates – home.html and about.html are used on each page and they display the expected content of “<h1>Homepage</h1>” and “<h1>About</h1>” respectively. We can use assertTemplateUsed and assertContains to achieve this.

Add following lines to Hello_app/tests.py


# Create your tests here.
class HomePageTexts(SimpleTestCase):
    ................................
#new methods
    def test_template_name_correct(self):
        response = self.client.get(reverse("home"))
        self.assertTemplateUsed(response,"home.html")

    def test_template_content(self):
        response = self.client.get(reverse("home"))
        self.assertContains(response,"<h1>Homepage</h1>")

    

class AboutPageTests(SimpleTestCase):
    ..............................
#new methods
    def test_template_name_correct(self):
        response = self.client.get(reverse("about"))
        self.assertTemplateUsed(response,"about.html")

    def test_template_content(self):
        response = self.client.get(reverse("about"))
        self.assertContains(response,"<h1>About</h1>")

Run Test

python3 manage.py test

The test failed as we have “<h1>Home Page</h1>” in templates/home.test but in test we are looking for “<h1>Homepage</h1>”.

Let us edit the templates/home.test as follow and run the test again.

{% extends "base.html" %}

{% block content %}
<h1>Homepage</h1>
{% endblock content %}