Reader small image

You're reading from  Building SPAs with Django and HTML Over the Wire

Product typeBook
Published inAug 2022
PublisherPackt
ISBN-139781803240190
Edition1st Edition
Tools
Right arrow
Author (1)
Andros Fenollosa
Andros Fenollosa
author image
Andros Fenollosa

Andros Fenollosa is a custom programming expert that works as a teacher, full stack developer, and mobile developer. He's a Web Designer, Web Programmer, and Apps Programmer, among other things ( PWA, Android and iOS ). He has a plethora of commercial expertise, having worked on projects in a variety of locales throughout the world.
Read more about Andros Fenollosa

Right arrow

Chapter 7: Creating a Real-Time Blog Using Only Django

In Chapter 6, Creating SPAs on the Backends, we learned essential features for setting up an SPA using HTML over WebSockets, such as changing pages, components, and sessions. We even went a step further by creating a server-side rendering system for each page so that search engines can index all content – a feature that didn’t require much effort as we are inside Django.

We now have the skills and maturity to make applications with all the features that SPA development entails. Now is the time! We will unify all the knowledge acquired in the creation of a perfectly prepared blog. Undoubtedly, this is an excellent exercise regardless of the language or framework that we want to assimilate; it encompasses all the basic tasks of any web development: querying, filtering, and adding to a database (search engine and comments), generating HTML from results (a list of articles and an individual page), use of views (SSR...

Technical requirements

All the code of the different sections can be found at the following link:

https://github.com/PacktPublishing/Building-SPAs-with-Django-and-HTML-Over-the-Wire/tree/main/chapter-7

As in other examples, I will start from the template that we built in Chapter 4, Working with the Database:

https://github.com/PacktPublishing/Building-SPAs-with-Django-and-HTML-Over-the-Wire/tree/main/chapter-4/initial-template

If you find some small differences, it is because I have made some minor adjustments. For example, I have named the project blog, the app website, and changed the path to http://blog.localhost, although, as always, you are free to name each element freely.

Creating models for the database

We will start by building two tables in the database: Post, which will contain the articles, and Comment, so that readers can leave their opinions next to the articles.

In app/website/models.py, add the following database structure:

from django.db import models
from django.utils.text import slugify
from django.urls import reverse
 
class Post(models.Model):
    # Fields: Title of the article, name of the author, 
    content of the article and date of creation.
    title = models.CharField(max_length=200, unique=True)
    author = models.CharField(max_length=20)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
 
    class Meta:
        ordering = ["-created_at"]
 
    @property
   ...

Generating fake articles and comments

After defining the database from the models, we are going to generate random data that we will use to work more comfortably.

We create make_fake_data.py with the following content:

from app.website.models import Post, Comment
from faker import Faker
 
# Delete all posts and comments
Post.objects.all().delete()
 
# Create fake object
fake = Faker()
 
def get_full_name():
    return f"{fake.first_name()} {fake.last_name()}"
 
# Create 30 posts
for _ in range(30):
    post = Post(
        title=fake.sentence()[:200],
        content=fake.text(),
        author=get_full_name()[:20],
    )
    post.save()
 
# Create 150 comments
for _ in range(150):
    comment = Comment(
        ...

Listing of articles

We have prepared the database through the models and by including fake information with the necessary elements, enabling us to focus on how the customer is going to visualize the content.

Before building the different pages, we will need a base for all templates. In app/website/templates/base.html, we include the main layout:

{% load static %}
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,
        user-scalable=no, initial-scale=1.0, maximum-
            scale=1.0, minimum-scale=1.0">
    <title>Example website</title>
    <link rel="stylesheet" href="{% static 'css/main.css' 
    ...

Adding an article search engine

Offering visitors pagination is a good idea to optimize resources and offer controlled navigation. In addition, including a search engine for articles will provide complete exploration. That is why we are going to integrate a text field to find articles by title.

In app/website/forms.py, we incorporate the following form, which will only have one field:

from django import forms
from . models import Comment
 
class SearchForm(forms.Form):
    search = forms.CharField(
        label="Search",
        max_length=255,
        required=False,
        widget=forms.TextInput(
            attrs={
                "id":...

Creating a static page

We are in a situation where we need to grow with new pages to split logic and HTML structures. The first step will be to create a static page.

We create app/website/templates/pages/about_us.html with simple text:

<h1> About us</h1>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad animi aut beatae commodi consectetur cumque ipsam iste labore laudantium magni molestiae nobis nulla quod quos tempore totam velit, voluptas voluptates!</p>

We edit the views (app/website/views.py), including about:

def about(request):
    return render(
        request,
        "base.html",
        { "page": "pages/about_us.html", "active_nav": 
           "about us"},
    ...

Moving between pages and generating a browser

Visitors need to navigate between different pages; a simple button structure and corresponding logic for loading the appropriate templates will need to be incorporated.

We are going to create a browser to dynamically jump between pages or, in other words, request the backend to render the page in the right place:

  1. The first step is to create a component with hyperlinks. We create a file in app/website/templates/components/_nav.html with the following structure:
    <ul class="nav__ul">
        <li>
            <a
                    href="#"
                    class="nav__link nav__link nav__link--page{% if active_nav == "all posts" %} active{% endif %}""
       ...

Implementing an individual page per article

We have the opportunity to create a page that renders an entire article, which will be the basis for the entire commenting system.

We create the template in app/website/templates/pages/single_post.html with basic but sufficient HTML for the minimum Post fields:

<section>
    {# Post #}
    <article>
        <header>
            <h1>{{ post.title }}</h1>
        </header>
        <div>{{ post.content }}</div>
        <footer>
            <p>{{ post.author }}</p>
        </footer>
    </article...

Adding a list of comments

The blog is functional: we can list articles, navigate between pages, paginate, and perform a search. But an essential element is still missing: comments. That’s why we are going to print all the comments that belong to an article.

We start by creating a template that lists all the comments. We add a new component in app/website/templates/components/_list_of_comments.html with the following content:

{% for comment in comments %}
    {% include "components/_single_comment.html" with 
       comment=comment %}
{% endfor %}

This, in turn, will need the app/website/templates/components/_single_comment.html component:

<article>
    <h2>{{ comment.author }}</h2>
    <p>{{ comment.content }}</p>
    <p>{{ comment.created_at }}</p>
</article>

In the views (app/website/views...

Adding new comments

If all the comments were written by us, it would be a bit immoral. We’re going to incorporate a form so that anyone reading the article can leave a personal opinion. If you don’t like what they say, you can always "manage" it with Django’s admin panel. But for now, let’s not be tricky; let’s focus on the more technical side.

First, we add the following form in app/website/forms.py:

class CommentForm(forms.ModelForm):
 
    author = forms.CharField(
        widget=forms.TextInput(
            attrs={
                "id": "author",
                "class": "input",
      ...

Offering an RSS feed

Tech blogs are often consumed by robots, in particular by feed readers. If we want to build a feed in Django, it’s really convenient. Django incorporates a framework called Syndication that automates tasks such as dynamic generation of XML, fields, and caching.

In app/website/feed.py, we add the following class that inherits from Feed:

from django.contrib.syndication.views import Feed
from django.urls import reverse
from .models import Post
 
class LatestEntriesFeed(Feed):
    title = "My blog"
    link = "/feed/"
    description = "Updates to posts."
 
    def items(self):
        return Post.objects.all()[:5]
 
    def item_title(self, item):
        return item.title
 
    def item_description(self, item):
  ...

Summary

We could consider this chapter as a consummation of all the skills acquired throughout the book. Not only are we able to incorporate a WebSockets server into Django, through channels; we now also have techniques to create a real-time, single-page application using Python. We now have a deep knowledge that matches the results we can achieve with other similar projects, such as LiveView in Phoenix (the most popular framework in the Elixir ecosystem), StimulusReflex, Turbo, Action Cable, or Hotwire in Ruby on Rails.

If we are looking to abstract part of the process, there are some frameworks within Django that can be useful, such as Django Sockpuppet or Django Reactor. Unfortunately, neither of them is receiving updates, although it is a great idea to find out how they are constructed in order to further expand our knowledge.

Although the backend is covered, it is still cumbersome to work with the frontend. Events have to be redeclared on every draw, and there are tasks...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Building SPAs with Django and HTML Over the Wire
Published in: Aug 2022Publisher: PacktISBN-13: 9781803240190
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Andros Fenollosa

Andros Fenollosa is a custom programming expert that works as a teacher, full stack developer, and mobile developer. He's a Web Designer, Web Programmer, and Apps Programmer, among other things ( PWA, Android and iOS ). He has a plethora of commercial expertise, having worked on projects in a variety of locales throughout the world.
Read more about Andros Fenollosa