Project Review: Django Blog

A full CRUD application using Django's full MVT architecture

waynelambert.dev Blog
Summary

Introduction

A blog was selected as a good application to build as it illustrates well-known web development patterns. It uses CRUD views, retrieval and rendering of database data and a sprinkling of JavaScript to improve the user experience.

The blog itself contains articles that document some of the challenges, processes, and design decisions for the portfolio in addition to more general programming, web development, and data science topics.

Features

  • Authentication and authorisation implemented for post creation, updation, and deletion
  • Two-factor authentication using a heavily customised implementation of the `Django Two-Factor Auth` package.
  • Predominantly built using Class-Based Views, therefore easier to maintain (in my opinion)
  • Efficient full word text search retrieval of data from PostgreSQL database with query optimisations
  • Tests built using the pytest framework and an in-memory PostgreSQL database
  • List view pagination on index, contents, author, category, and search results pages
  • Detail view pagination cycling through individual posts
  • Conditionally visible category sidebar including count of posts in each category
  • Contents page allowing visitors to see full list of posts
  • Media storage integrated with Amazon S3
  • Site emails implemented with Amazon's Simple Email Service (SES)
  • RSS Feed
  • Sitemap implementation to facilitate search engine indexing
  • Highly customised and secured 'Admin' pages/interface

Objectives

I set out to build a blog that enabled intuitive navigation and discovery of the blog's content using a clean and minimalistic interface. Features such as a category sidebar with the number of posts included within each category should enable the user to find other posts that might be of interest.

The blog should include a detailed amount of metadata which informs the reader on how useful the blog's article is. One of my personal dislikes is when I'm reading a blog post and there's no created or updated date on the post. This leaves me wondering if the solution provided really is aligned to the challenge I'm facing.

The Approach & Solution

Firstly, I drafted a database schema with a rough sketch on my notepad. Following this, I created the 'Category' and 'Post' models within the 'blog' app.

I decided to structure the relationships between categories and posts as a many-to-many relationship. It would have been easier to develop a solution using a one-to-many relationship however, it seemed reasonable to me that a post could fall into many different categories.

Following this, in a separate app called 'users', I created a 'Profile' model which has a one-to-one relationship with Django's default 'User' model. These are connected using Django signals whereby when an instance of 'User' is created, it sends a signal to the custom 'Profile' model to simultaneously create an instance of the 'Profile' model.

Following the implementation of the models, I designed the URL structure of the application. Working in this way helped me to decide upon the various views that needed to be created. I have learned that it's best to work in order of most generic to most specific in terms of creating the URLs/views.

The final stage was to render the templates which is of course was an iterative process requiring revisions to the models and views as better or more desirable options become apparent.

During development, I have refactored to implement a model manager which represents a queryset for published posts which is re-used repeatedly throughout the project. This has moved a lot of the implementation logic away from the views and towards the models. This has made it easier to remove any duplicate SQL queries from the views in addition to making the code easier to maintain, and re-use.

Evaluation

If I were to repeat the project, I would create a custom user model which would use an email address for registration rather than a username. I think that using usernames is an outdated way of signing up for a website. It's more difficult for a user to remember their username than their email address. This fits my own personal preferred and biased method and of signing up to web services.

Additionally, due to privacy concerns, I don't believe in using Google or Facebook's expedited login buttons. They're very convenient at the point of registration but expensive in terms of the data that you're giving away. Some might argue the very valid point that they're extremely secure because of the resources that they put into ensuring their platforms are secure, however I still believe this is at the expense of user privacy. If it becomes easy to use Apple's newer sign in with apple button, then I may revisit this because of their approach to privacy.

Changing over to a custom user model at this point would require a considerable amount of effort to derive very little benefit. I have used this pattern in a subsequent project within one of my private repositories.

Languages, Technologies & Skills Used

In approximate order of frequency used...
Languages: Python, JavaScript, HTML, Sass
Frameworks / Services: Django, Bootstrap, pytest, Font Awesome, Amazon S3, Amazon SES
Software: VS Code, DataGrip, Firefox Dev Tools
Infrastructure: GitHub, Docker, Poetry, Node
Notable Packages: Node Sass, Django Crispy Forms, Django Widget Tweaks, Whitenoise, Tiny MCE Editor, Boto3, Django Recaptcha, Pillow, Django Two Factor Auth