Call Overmortal now at 1 (540) 491-0374 or for more information!

Extending Django's Flatpages

If you're a Django developer and you've had to deal with static content, you're very familiar with Django's flatpages application and middleware. Most developers are content with implementing this solution and leaving it "as is" for the content site editors who handle those pages. However, in any company with an SEO employee, or a marketing employee with SEO knowledge, you'll often run into a situation where meta tags need to be managed along with the static content. Django's flatpages don't have this ability by default, but it is something that you can easily add to your application.

Rather than replace Django's flatpages or extend the default functionality and expand its database table, we decided to leave the flatpages as they were and instead focus on adding the meta data through a secondary database table. For this, we imported the default Flatpage model and created our meta data model in a separate model.py file:

from django.db import models
from django.conf import settings
from django.contrib.flatpages.models import FlatPage
from datetime import datetime

class Meta(models.Model):
    flatpage = models.OneToOneField(FlatPage)
    keywords = models.CharField(max_length = 255)
    description = models.TextField()
    active = models.BooleanField()
    date_created = models.DateTimeField()
    date_modified = models.DateTimeField()
    def __unicode__(self):
        return self.flatpage.title
    def save(self):
        if not self.id:
            self.date_created = datetime.now()
            self.date_modified = datetime.now()
        super(Meta, self).save()

Notice how we have a one-to-one relationship between the flatpages and the meta model. We also have some of our standard database columns.

Once this is finished, we need to create the proper admin classes:

from django.contrib import admin
from django.contrib.flatpages.admin import FlatPageAdmin as StockFlatPageAdmin
from models import *

class MetaAdmin(admin.ModelAdmin):
    list_display = ('flatpage','date_created',)
    list_filter = ('flatpage',)
    ordering = ('flatpage',)
    search_fields = ('flatpage',)

admin.site.register(Meta, MetaAdmin)

class MetaInline(admin.StackedInline):
    model = Meta

class FlatPageAdmin(StockFlatPageAdmin):
    inlines = [MetaInline]

admin.site.unregister(FlatPage)
admin.site.register(FlatPage, FlatPageAdmin)

Notice how we imported the standard admin class for the flatpages applications as "StockFlatPageAdmin" and then subclassed it with a new "FlatPageAdmin" class. This is so we can extend the admin flatpages to include the meta fields inline, keeping all the static content and the meta data on one page. We then have to unregister the default flatpage admin class and then register the new subclassed version.

Finally, in order to continue using the flatpages/default.html template file as the singular file for handling flatpage content, we need to create helper tags to bring out the keywords and description:

from django import template
from django.contrib.flatpages.models import FlatPage
from pages.models import *

register = template.Library()

@register.tag
def meta_keywords(parser, token):
    tag_name, flatpage_id = token.split_contents()
    return MetaKeywordsObject(flatpage_id)

class MetaKeywordsObject(template.Node):
    def __init__(self, flatpage_id):
        self.flatpage_id = template.Variable(flatpage_id)
    def render(self, context):
        try:
            return Meta.objects.filter(flatpage = self.flatpage_id.resolve(context))[0].keywords
        except:
            return ''

@register.tag
def meta_description(parser, token):
    tag_name, flatpage_id = token.split_contents()
    return MetaDescriptionObject(flatpage_id)

class MetaDescriptionObject(template.Node):
    def __init__(self, flatpage_id):
        self.flatpage_id = template.Variable(flatpage_id)
    def render(self, context):
        try:
            return Meta.objects.filter(flatpage = self.flatpage_id.resolve(context))[0].description
        except:
            return ''

After implementing the above, you would just load your flatpage helper in the flatpages/default.html file and then add the custom tags while passing in the flatpage ID:

<meta name="keywords" content="{% meta_keywords flatpage.id %}" />
<meta name="description" content="{% meta_description flatpage.id %}" />

Now your SEO people can easily add meta tag information to your static content via Django's flatpages.