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()1011 def __unicode__(self):12 return self.category1314 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()1314 def __unicode__(self):15 return self.category1617 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)2223 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!