How To Optimize Images in Django Using ImageEngine

Written by jonarnes | Published 2021/08/12
Tech Story Tags: django | resize-image-in-django | django-tips | how-to-django | image-processing | image-cdn | responsive-images | image-optimization

TLDR The fastest way to communicate to an end-user is directly through visual communications and images are the most viable way to deliver your message. Images require the bulk of web page loading time, which is why optimizing them while delivering quality content should be of prime concern. We’ve created a dummy Django Web-App simulating a typical e-commerce store. We hope to provide some good insights about the performance boost a typical application can have with just a raw integration of image optimization CDN’s.via the TL;DR App

The fastest way to communicate to an end-user is directly through visual communications and images are the most viable way to deliver your message. They are not just for decoration but deliver your philosophy and intent as an organization.

Images require the bulk of web page loading time, which is why optimizing them while delivering quality content should be of prime concern.

This article can help you if you’re a developer/manager/product owner using Django for web application development. We will move through the following phases in this article:

  • Motivation
  • Implementation of ImageEngine with Django
  • Results in Web Performance

Motivation

User growth has been directly linked with performance in recent years considering the bloating website sizes. In 2017, Pinterest reported that with a performance improvement of a 40% decrease in waiting time, they reported a 15% increase in organic traffic and a 15% increase in signups. Compounded growth like this leads to a high growth factor for all web conversions.

Integrating ImageEngine with Django

For the purpose of this demo and practical application, we’ve created a dummy Django Web-App simulating a typical e-commerce store. You can view the deployed website on Heroku.

All of the code is present on Github for reference. With this open-source typical Django application, we hope to provide some good insights about the performance boost a typical application can have with just a raw integration of image optimization CDN’s such as ImageEngine.

Let’s have a walkthrough of the code:

urlpatterns = [
   path('', views.store, name='store'),
   path('cart', views.cart, name='cart'),
   path('checkout', views.checkout, name='checkout'),
]

The urls.py requires no changes before and after the integration.

def store(request):
   products = Product.objects.all()
   context = {'products': products}
   return render(request, 'store/store.html', context)

The view has a function for our store listing page that is self-explanatory. For adding the CDN to the template, we can add it via context from views. So we modify the views.py by adding a base context that can be extended by every view function.

BASE_CONTEXT = {
   'MEDIA_CDN': settings.MEDIA_CDN,
}   

def store(request):
   products = Product.objects.all()
   context = BASE_CONTEXT
   context['products'] = products
   return render(request, 'store/store.html', context)

Now we have a MEDIA_CDN URL injected into the context for the template files.

Next, we’ve template files such as store.html where we wish to display images. This can be done by prepending the media URL to the relative images. (store.html)

{%if product.image %}
     <img
       class="img-responsive product-image"
       src="{{ MEDIA_CDN }}{{ product.image.url}}"
     />
{%else %}
     <img class="thumbnail" src="{%static 'images/placeholder.png' %}" />
{% endif %}

Since MEDIA_CDN is injected into the code, we just need to make one more change i.e. add the MEDIA_CDN URL onto the Django configuration as below (settings.py):

MEDIA_CDN = env.str('MEDIA_CDN', '')

In .env:

MEDIA_CDN=https://xxxxx.cdn.imgeng.in

Our Django app is now ready to be deployed, we just need to set up our account on ImageEngine to get the MEDIA_CDN configuration URL.

Just head over to ImageEngine and signup.

At the end of the process, you get a unique ImageEngine Delivery Address.

Now just copy the Delivery Address and put it in the .env file or in Heroku in the environment variables.

MEDIA_CDN=https://xxxxxx.cdn.imgeng.in
DEBUG=True

And we’ve successfully integrated ImageEngine with our Django App. Let’s now analyze the performance improvement upon this incorporation.

Results and Observations

We will divide this part into 2 sub-sections:

  1. Raw Website Analysis
  2. ImageEngine Integration with Django Results

Raw Website Analysis

First, we analyze the Django app with locally placed images in the same web location as the Heroku app. These are standard images and since there are only a very small number of images on the listing page we can expect a decent score. We are using Google’s Lighthouse tests for this analysis.

Google’s Lighthouse is an open-source tool that can be used to analyze the web performance of any website by self-deploying their code or using Chrome’s inbuilt console or simply by adding the website’s URL in at web.dev. For the purpose of this demo, we will use web.dev since it has a simpler user experience.

The area of focus for our demo is Performance. 74 might not look that bad, but considering our listing pages have only 6 images and no bloated CSS/JS code is present nor are there many external dependencies, it’s actually quite poor.

Upon deeper analysis, we find the main reason for this score is the Largest Contentful Paint (LCP). LCP is the render time taken for the largest image/text within a web page. So, when the image first starts loading and gets completely rendered, that is the time span which is referred to as the largest contentful paint.

Ideally, the Largest Contentful Paint should be less than 2.5 seconds. This helps the website be performant, resulting in lower bounce rates. It becomes particularly important for cases of lower network speeds such as 3g/4g and lower processing powers of mobiles compared to desktops. Upon diagnosing the issue we find more areas for resolutions in order of priority as follows:

  1. Properly sized images
  2. Serving images in next-gen formats
  3. Adding efficient cache policy
  4. Reducing enormous payloads

Now, let’s move to the next section and examine the performance benefits with our Django app upon integrating with ImageEngine:

ImageEngine Integration with Django Results

With the simplest integration, we can see a mighty increase in the performance score of our web app from 74 to 92 with less than an hour of work and easy-to-use configuration. There are no complex code pieces to keep track of and our website has achieved a highly performant web reputation.

Observations

The effects of such an approach are quite obvious, in terms of performance we see a whopping 18% increase in the website’s performance. The biggest factor i.e. Largest Contentful paint had a decrease in the time-span by almost 86%.

This was all possible because of ImageEngine’s automatic image compression (eg: the original headphones image size reduced from 2.2MB to 259kb, approximately 87% reduction in size) and image-serving mechanism in next-gen image formats such as WebP and AVIF, which is evident from the network call seen using Chrome Devtools.

Conclusion

Hopefully, this demo served as a good example of how a simple integration of the Django Web App with ImageEngine can dramatically increase your website’s performance.

Apart from direct effects, a number of side effects of this minor fix include minimal developer man-hours, simple configuration at project level short of any complex code. In terms of business, lower bounce rates on the website, longer time-on-site, and even a better Google ranking in the distant future.


Written by jonarnes | I'm a mobilist and web-believer. I spend my days making the web faster, caring for the mobile web surfers.
Published by HackerNoon on 2021/08/12