How to create a fullstack application using Django and Python Part 25

Tuesday, October 8, 2024 at 3:08 PM | 3 min read

Last modified on Monday, May 25, 2026 at 10:34 PM

#fullstack development, #macOS, #django, #django-avatar, #gravatar, #humanize, #python3, #series

Toy avatar in the grass

Photo by Oliver Sharp on unsplash.com

Important Note: Before committing anything to Git or pushing anything to remote, please visit How to create a fullstack application using Django and Python Part 4 where I discuss how to add the python-dotenv package to the Django site and why it is crucial to do it. This article assumes you have a working knowledge of Git.

Table of Contents

Adding Humanize

In this section, we are going to add the Humanize package to our Django project. The humanize package contains various common humanization utilities, like turning a number into a fuzzy human-readable duration ("3 minutes ago") or into a human-readable size or throughput1.

Humanize is still a built-in package, but we have to use the following command in order to install the latest version and make it work properly:

python3 -m pip install --upgrade humanize

Which returns the following in Terminal:

Collecting humanize Downloading humanize-4.11.0-py3-none-any.whl.metadata (7.8 kB) Downloading humanize-4.11.0-py3-none-any.whl (128 kB) Installing collected packages: humanize Successfully installed humanize-4.11.0

Next, I add homanize to INSTALLED_APPS in django_boards/settings.py:

# settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', 'boards', 'accounts', 'dotenv', 'pylint', 'graphviz', 'djlint', 'coverage', 'widget_tweaks', 'soupsieve', 'bs4', 'html5lib', 'markdown', 'humanize', ]

Now we can use it in the templates.

Adding Humanize naturaltime to templates/topics.html

<!-- templates/topics.html --> {% extends "base.html" %} {% load humanize %} <!--must be added AFTER b otherwise the package will not work --> {% load humanize %} ... <table class="table"> <thead class="thead-inverse"> <tr> <th>Topic</th> <th>Starter</th> <th>Replies</th> <th>Views</th> <th>Last Update</th> </tr> </thead> <tbody> {% for topic in topics %} <tr> <td> <a href="{% url 'topic_posts' board.pk topic.pk %}">{{ topic.subject }}</a> </td> <td>{{ topic.starter.username }}</td> <td>{{ topic.replies }}</td> <td>{{ topic.views }}</td> <!-- humanize --> <td>{{ topic.last_updated | naturaltime }}</td> </tr> {% endfor %} </tbody> </table> ...

And that's it for humanize. You can add it wherever else you want. I am going to just stick with it here for now.

Adding a Gravatar

Now we are going to add Gravatar. Gravatar is an easy way to add user profile pictures. I used to use it a lot in my WordPress sites.

Creating boards/templatetags/gravatar.py

# boards/templatetags/gravatar.py import hashlib from urllib.parse import urlencode from django import template from django.utils.safestring import mark_safe from django.conf import settings register = template.Library() @register.filter def gravatar_url(user): email = user.email.lower().encode('utf-8') default = 'mm' size = 40 url = 'https://www.gravatar.com/avatar/{sha256}?{params}'.format( sha256=hashlib.sha256(email).hexdigest(), params=urlencode({'d': default, 's': str(size)}) ) return url @register.filter def gravatar(user): url = gravatar_url(user) return mark_safe(f'')

This (updated) code is taken from the Gravatar Django documentation and adapted to our project.

Adding Gravatar functionality to templates/topic_posts.html

{% extends "base.html" %} {% load gravatar %} ...

However, these changes alone don't result in the implementation of user gravatars.

Installing the django-avatar package

Next, we are going to install the django-avatar package. It has the ability to default to avatars provided by third party services (like Gravatar or Facebook) if no avatar is found for a certain user. django-avatar automatically generates thumbnails and stores them to your default file storage backend for retrieval later.

To install django-avatar, we need to run the following command:

pip install django-avatar

Which returns the following:

Collecting django-avatar Downloading django_avatar-8.0.1-py3-none-any.whl.metadata (2.8 kB) Collecting Pillow>=10.0.1 (from django-avatar) Downloading pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl.metadata (9.2 kB) Collecting django-appconf>=1.0.5 (from django-avatar) Downloading django_appconf-1.0.6-py3-none-any.whl.metadata (5.4 kB) Collecting dnspython>=2.3.0 (from django-avatar) Downloading dnspython-2.7.0-py3-none-any.whl.metadata (5.8 kB) Requirement already satisfied: django in /Users/mariacam/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from django-appconf>=1.0.5->django-avatar) (5.1) Requirement already satisfied: asgiref<4,>=3.8.1 in /Users/mariacam/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from django->django-appconf>=1.0.5->django-avatar) (3.8.1) Requirement already satisfied: sqlparse>=0.3.1 in /Users/mariacam/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from django->django-appconf>=1.0.5->django-avatar) (0.5.1) Downloading django_avatar-8.0.1-py3-none-any.whl (67 kB) Downloading django_appconf-1.0.6-py3-none-any.whl (6.4 kB) Downloading dnspython-2.7.0-py3-none-any.whl (313 kB) Downloading pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl (3.4 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.4/3.4 MB 3.2 MB/s eta 0:00:00 Installing collected packages: Pillow, dnspython, django-appconf, django-avatar Successfully installed Pillow-10.4.0 django-appconf-1.0.6 django-avatar-8.0.1 dnspython-2.7.0

Adding django-avatar to django_boards/settings.py

# django_boards/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', 'boards', 'accounts', 'dotenv', 'pylint', 'graphviz', 'djlint', 'coverage', 'widget_tweaks', 'soupsieve', 'bs4', 'html5lib', 'markdown', 'avatar', # added ]

Migrating the database

python manage.py migrate

Which, for me, returned the following in Terminal:

Operations to perform: Apply all migrations: admin, auth, avatar, boards, contenttypes, sessions Running migrations: Applying avatar.0001_initial... OK Applying avatar.0002_add_verbose_names_to_avatar_fields... OK Applying avatar.0003_auto_20170827_1345... OK

The default directory for django avatars

The default directory for django-avatar is "avatars", and the structure and contents of that directory is the following:

- django_boards/ ... - avatars/<user_id> - <user_id>/ - resized/ - 80/ - 10551051-copy.png - 10551051.png - 10551051-copy.jpeg - 10551051.jpg

There is much more to do regarding user avatars/gravatars. In the next section, we will add a profile model, view, and template, and will add the functionality for uploading a gravatar/avatar locally_as well as wrapping up a few minor details relating to the last_update field for a post, further pagination tweaks, and updating the test_view_reply_topic_tests.

Conclusion

In this section, I added the Humanize package to our templates/topics.html, added the Gravatar package for user gravatars, and added the django-avatar package for automatic implementation of a user avatar when one is absent.

Footnotes

  1. Throughput is a measure of how much work or information a system can process in a given amount of time. In programming, throughput can refer to the amount of work completed in a given period of time, or the rate at which features are delivered.