This site runs best with JavaScript enabled.

Django Textile/Markdown Template Caching Speedup

Photo by julian mora on Unsplash


Speeding up a Django site by transforming text during database saves.

I've been putting some time into updating an old site this weekend. I noticed that the homepage was taking a long time to load - around 5 to 8 seconds. Not good.

I tried caching queries but it didn't help at all. Then I realized it was most likely due to my decision long ago to use textile to render text to HTML.

The site is located at direct-vs-dish.com. It essentially compares DIRECTV to DISH Network. On the home page is a number of features. Each feature represents a database record. Here is my original model for the features:

1class Feature(models.Model):
2 category = models.CharField(max_length=255)
3 slug = models.SlugField()
4 overview = models.TextField(blank=True, null=True)
5 dish = models.TextField(blank=True, null=True)
6 directv = models.TextField(blank=True, null=True)
7 dish_link = models.URLField(blank=True, null=True)
8 directv_link = models.URLField(blank=True, null=True)
9 order = models.PositiveSmallIntegerField()
10
11 def __unicode__(self):
12 return self.category
13
14 class Meta:
15 ordering = ['order']

Three of the above fields use textile: overview, dish, & directv. I currently have 14 feature records. So that is a potential of 42 textile conversions for the home page.

In order to cache these textile conversions, I added three new fields. I then added a save method to populate the cached html fields. My model now looks like this:

1class Feature(models.Model):
2 category = models.CharField(max_length=255)
3 slug = models.SlugField()
4 overview = models.TextField(blank=True, null=True)
5 overview_html = models.TextField(blank=True)
6 dish = models.TextField(blank=True, null=True)
7 dish_html = models.TextField(blank=True)
8 directv = models.TextField(blank=True, null=True)
9 directv_html = models.TextField(blank=True)
10 dish_link = models.URLField(blank=True, null=True)
11 directv_link = models.URLField(blank=True, null=True)
12 order = models.PositiveSmallIntegerField()
13
14 def __unicode__(self):
15 return self.category
16
17 def save(self, **kwargs):
18 self.overview_html = textile(self.overview)
19 self.dish_html = textile(self.dish)
20 self.directv_html = textile(self.directv)
21 return super(Feature, self).save(kwargs)
22
23 class Meta:
24 ordering = ['order']

I use the Django admin to edit features so I added some styling to hide the cached HTML fields with an option to show them if you want to see what has been converted and cached.

1class FeatureAdmin(admin.ModelAdmin):
2 list_display = ('category', 'order')
3 prepopulated_fields = {"slug": ("category",)}
4 fieldsets = (
5 (None, {
6 'fields': ('category', 'slug', 'overview', 'dish', 'dish_link',
7 'directv', 'directv_link', 'order')
8 }),
9 ('Auto Generated', {
10 'classes': ('collapse',),
11 'fields': ('overview_html', 'dish_html', 'directv_html'),
12 }),
13 )
14admin.site.register(Feature, FeatureAdmin)

My template tags went from this:

1{{ feature.overview|textile }}

To this:

1{{ feature.overview_html|safe }}

This has dropped my homepage rending time to about 750ms. This is without any caching of queries. Huge win!

Discuss on TwitterEdit post on GitHub

Share article
Dustin Davis

Dustin Davis is a software engineer, people manager, hacker, and entreprenuer. He loves to develop systems and automation. He lives with his wife and five kids in Utah.

Join the Newsletter



Dustin Davis