Django SEO documentation contents

Getting started

Welcome to Django SEO

Design

Django SEO is a library that allows you to attach metadata to:

  • Paths
  • Model instances
  • Models
  • Views

It is a library because you, the developer, have full control over what sort of information is attached to the above, and how it is eventually displayed. To use this library, you need to define the metadata you want and add the output to your templates. Everything else (retrieval, formatting, escaping, caching) is handled for you.

Metadata can be edited by site administrators in the Django Admin, either in a centralised place, or inline with the relavent models. As requirements change, it may become necessary to add new metadata fields. Having the metadata definition confined to a single, short class means that it is easy to update (even for amateur programmers).

What’s next?

If you would like to get a feel for how the library works, you might like to read the site administrator’s guide.

To get started, you can read the Quick install guide or work through the tutorial. Django experts may save time use the 60 second tutorial.

Quick install guide

The easiest way to install Django SEO is to use use pip, if you have it:

pip install DjangoSEO

If you don’t, and you prefer the old school easy_install, then the following command is for you:

easy_install DjangoSEO

Not So Quick install

If you don’t have easy_install or pip installed, you will need to do things manually. Firstly, install Django (version 1.1 or newer) by following the installation instructions at http://docs.djangoproject.com/en/dev/intro/install/.

Next download the Django SEO release from http://github.com/willhardy/django-seo. To unpack and install it, run the following from your shell:

tar xvzf DjangoSEO-1.0.tar.gz
cd DjangoSEO-1.0/
python setup.py install

That’s it, you’ve installed everything you need to install. You can now try the tutorial.

Development version

For those you like to help out, you can check out the development version here:

git clone git@github.com:willhardy/django-seo.git

Django SEO Framework Tutorial

Adding SEO to your Django site is easy, you need to do two things:

  • Define which metadata fields you need
  • Add the output to your templates

Before we start

This tutorial assumes you already know how to use Django, and that you have a site with some apps already up and running. It assumes you have installed the library somewhere where python can get it, and that you’ve added rollyourown.seo to your INSTALLED_APPS setting.

Metadata definition

You can define which fields appear in your metadata by creating a class that subclasses seo.Metadata. For example, create a new file called seo.py in an app on your site:

from rollyourown import seo

class MyMetadata(seo.Metadata):
    title       = seo.Tag(head=True, max_length=68)
    description = seo.MetaTag(max_length=155)
    keywords    = seo.KeywordTag()
    heading     = seo.Tag(name="h1")

Done! The above definition outlines four fields:

  • A <title> field, appearing in the head and limited to 68 characters (most search engines will the first 68 characters before any truncating takes place).
  • A <meta> tag for the description, with a maximum length of 155 (again, to appear in search engine results). <meta> tags are always set to appear in the head.
  • A <meta> tag for keywords. (you could also use seo.MetaTag).
  • A <h1> tag for headings, which does not appear in the document head.

If you run syncdb you will also notice that four new models are created:

  • One to attach the metadata to paths
  • One to attach the metadata to model instances
  • One to attach the metadata to models
  • One to attach the metadata to views

Setting up the Admin

To view and edit these in Django’s admin, add the following to your urls.py:

from rollyourown.seo.admin import register_seo_admin
from django.contrib import admin
from myapp.seo import MyMetadata

register_seo_admin(admin.site, MyMetadata)

You should now see the four models in the admin, and will be able to add metadata for each of the fields you defined earlier.

Adding the output to your templates

Once again, there isn’t much to do here. Simply pick a suitable template. Most often this will be base.html, which is extended by most other templates. After loading the seo template library, simply output all the head elements add the tag {% get_metadata %}, like this:

{% load seo %}
<html>
<head>
  {% get_metadata %}
</head>
<body>
    <p>I like gypsy Jazz!</p>
</body>
</html>

Note

Make sure you have "django.core.context_processors.request" listed in your site’s TEMPLATE_CONTEXT_PROCESSORS setting. This provides {% get_metadata %} with the current path, allowing it to automatically select the relevant metadata.

Seeing it in action

Using the admin site, add some new metadata, attaching it to a (valid) path of your choice. Open up your browser and visit the path, to hopefully see something like this in the page source:

<html>
<head>
  <title>My Title</html>
  <meta name="description" content="My description" />
  <meta name="keywords" content="My, list, of, keywords" />
</head>
<body>
    <p>I like gypsy Jazz!</p>
</body>
</html>

Fine tuning the display

Notice that all of the head elements have automatically been added where the {% get_metadata %} tag was used. But you’ll also notice that the heading is missing. Because the heading was not defined to appear in the head, it was not automatically added. To do that, you will have to explicitly add it to the template. Like this:

{% load seo %}
<html>
<head>
  {% get_metadata as my_meta %}
  {{ my_meta }}
</head>
<body>
    {{ my_meta.heading }}
    <p>I like gypsy Jazz!</p>
</body>
</html>

Now your page will show the heading you wanted. Notice that {% get_metadata %} no longer outputs the head metadata, but instead creates a new variable my_meta. The line following it ({{ my meta }}) outputs the head elements for you, and can be used to access other fields, such as the heading.

But what if your <h1> needs to have a class? You can also retrive the value directly, like this:

<h1 class="special">{{ my_meta.heading.value }}</h1>

What next?

This is just an introduction to the framework. There are a number of other features including:

  • Variable substitution to access model instance attributes (for model-based metadata) and view context (for view-based metadata)
  • Optional support for django sites framework
  • Optional i18n (internationalisation) support
  • Optional caching
  • Auto-population for missing values using other fields, attributes, methods, callables or literal values
  • Grouped fields, for both admin editing and output
  • Hidden fields, ie not editable in admin
  • API for custom fields to provide customised rendering, cleaning, etc

Complete details on these are provided in the API reference.

Django SEO Framework 60-Second-Tutorial

This is an inordinately brief tutorial, for Django experts who don’t like to waste time.

Step One

  • Add rollyourown.seo to INSTALLED_APPS
  • Make sure "django.core.context_processors.request" is listed in TEMPLATE_CONTEXT_PROCESSORS

Step Two: Definition

Create a file seo.py in any app, with the following simple definition:

from rollyourown import seo

class MyMetadata(seo.Metadata):
    title       = seo.Tag(head=True, max_length=68)
    description = seo.MetaTag(max_length=155)
    keywords    = seo.KeywordTag()
    heading     = seo.Tag(name="h1")

Run syncdb

Step Three: Admin

To edit the data in the admin, call register_seo_admin with the admin site and the metadata definition:

from rollyourown.seo.admin import register_seo_admin
from django.contrib import admin
from myapp.seo import MyMetadata

register_seo_admin(admin.site, MyMetadata)

Step Four: Adding to templates

To get the metadata in your templates, use the {% get_metadata %} template tag:

{% load seo %}
{% get_metadata %}

The above renders like this:

<title>My Title</html>
<meta name="description" content="My description" />
<meta name="keywords" content="My, list, of, keywords" />

Epilogue: A little more control

If you save the metadata object as a variable, you’ll be able to access the fields individually:

{% load seo %}
{% get_metadata as metadata %}

{{ metadata }}

{{ metadata.heading }}
<h1 class="special">{{ my_meta.heading.value }}</h1>
<p>{{ my_meta.description.value }}</p>

The following is rendered:

<title>My Title</html>
<meta name="description" content="My description" />
<meta name="keywords" content="My, list, of, keywords" />

<h1>My Heading</h1>
<h1 class="special">My Heading</h1>
<p>My description</p>

What next?

This is just an introduction to the framework. There are a number of other features including:

  • Variable substitution to access model instance attributes (for model-based metadata) and view context (for view-based metadata)
  • Optional support for django sites framework
  • Optional i18n (internationalisation) support
  • Optional caching
  • Auto-population for missing values using other fields, attributes, methods, callables or literal values
  • Grouped fields, for both admin editing and output
  • Hidden fields, ie not editable in admin
  • API for custom fields to provide customised rendering, cleaning, etc

Complete details on these are provided in the API reference.

See also

If you’re new to Django and Python, you may want to read up about them. A useful starting guide is in the Django documentation.

API Reference

SEO data definition

The SEO data definition is used to create a series of Django models to store metadata. The definition itself, is similar to the definition of Django models. Here is a simple example:

class BasicExample(seo.Metadata):
    title       = seo.Tag(head=True)
    keywords    = seo.MetaTag()
    description = seo.MetaTag()
    heading     = seo.Tag(name="h1")

This eventually produces some models, which stores four different pieces of metadata. The behaviour can be customised by passing attributes, as the heading field does.

Fields

The are four built-in metadata fields: seo.Tag(), seo.MetaTag(), seo.KeywordTag() and seo.Raw(). The full range of attributes for each type of field is listed below.

seo.Tag

This is your standard, every-day HTML tag, like <title> or <h1>.

class seo.Tag(**options)
name

Name of this tag. For example, if name is set to h1, the following will be rendered: <h1>My heading</h1>. By default, this is set to the attribute’s name.

valid_tags

See below for details. This defaults to a list of inline HTML elements.

seo.MetaTag

Because meta tags are a common place to store metadata, a special field is provided. This field is useful, as it has attribute escaping built in (for eg quotations).

class seo.MetaTag(**options)
name

The value of the meta element’s name attribute. For example, if name is set to "description", the following will be rendered: <meta name="description" content="My description" /> By default, this is set to the attribute’s name.

seo.KeywordTag

This is simply a MetaTag with the default name keywords and small customisations in the admin. When a value is entered over multiple lines, each line is joined using a comma. In the future, more substantial admin customisations may be employed to help add keywords.

class seo.KeywordTag(**options)
name

The value of the meta element’s name attribute. By default, this is set to keywords.

seo.Raw

The raw field allows the admin user to enter raw html data (if you want them to!). You can of course restrict the tags available, to ensure that the admin users cannot inadventently break the site (they are after all not playing the role of website developer). By default, a Django TextField is used for this field.

class seo.Raw(**options)
All fields:

All three fields (Tag, MetaTag and Raw) accept the following parameters. Any unknown parameters will be passed onto the underlying Django field (usually a CharField).

field

The underlying Django field, either a field class or a field instance. By default this is usually a CharField.

Boolean, determines if this should automatically be included in the head

editable

Boolean, determines if this should be user editable (in the admin), otherwise the default value will always be used.

choices

A list of values, which will be passed to the underlying Django field, making them available in the admin (usually as a drop down list).

verbose_name

A user friendly name for this field, which appears in the admin.

help_text

A description of what should go in this field, for the admin. If a default value is given (using the populate_from parameter), a description of what will be included will appear automatically at the end of the help_text.

populate_from

A default value, when no data is available (as seen above for each of the fields). If you do not set this, it will be set to None, which means the field will not appear. You can pass a callable, name of a field, name of a method or a literal value. The value is resolved in the following way:

  1. if a callable is provided, call it each time the value is to be displayed
  2. if name of field or method is provided, use the value provided by that field or method
  3. otherwise, treat the given value as a literal value. Literal values can also be explicitly marked.

If a callable or the name of a method is provided, it is called (at run time) with the metadata as the first argument (or of course self) and a variable set of keyword arguments. For this reason, you should always use **kwargs and default values for the parameters you use. Return None to leave out the tag/meta tag/raw data. For example:

def default_title(metadata, model_instance=None, **kwargs):
    if model_instance:
        return "My Website: %s" % model_instance.name
    else:
        return None

Currently, the keywords are model_instance, view_name, content_type, path. They won’t all appear at once, and future version may include more information.

If you provide a callable, you can describe what the callable will return for the benefit of admin users. Do this by setting the short_description attribute on the callable. For example:

def default_title(metadata, **kwargs):
    return "My Website"
default_title.short_description = "Standard title will be used"
max_length

This is passed directly onto the Django field. By default, it is set to an arbitrary 511 characters, but it is worth setting this manually. For a <title> tag, a limit of 68 will ensure the title fits into most search engine results. For the description meta tag, a limit of 155 characters will be safe. If the field has been set to use a TextField Django field, then max_length cannot be specified.

valid_tags

Tags listed here are valid, all other tags will be stipped from the output.

If this is not set, and head is set to True, then this will default to:

valid_tags = "head title base link meta script".split()

otherwise, it is set to None, allowing all tags.

Meta Options

The metadata definition can take a number of options that are provided in a Meta class (sorry for the name), much like Django models and forms do. For example:

class BasicExample(seo.Metadata):
    title       = seo.Tag(head=True)
    keywords    = seo.MetaTag()
    description = seo.MetaTag()
    heading     = seo.Tag(name="h1")

    class Meta:
        use_sites = True
        use_cache = True
        use_i18n = True
        groups = {'optional': ('heading',)}
        seo_models = ('my_app', 'flatpages.FlatPage')
        seo_views = ('my_app', )
        backends = ('path', 'model', 'view')
        verbose_name = "My basic example"
        verbose_name_plural = "My basic examples"
Meta.use_sites

Boolean, determines if all metadata should be linked to a site in the sites framework. Each metadata entry can then be optionally associated with a site, meaning it will only appear if the selected site is the current site. If site is set to null on a metadata entry, it will be used for all sites that are missing an explicit entry. By default, use_sites is False.

Meta.use_cache

If this is True caching is enabled, meaning that each of the final values for each field on a given path will be cached. You may like to turn this off if you are caching the final output in any case. By default, use_cache is False.

Meta.use_i18n

If this is True, an extra field for language selection is provided. Metadata will only be returned for the given language. By default, use_i18n is False.

Meta.groups

Logical grouping of fields. This will be used in the admin, as well as in the output. Templates can access this directly to output a number of grouped fields at once.

Meta.seo_models

List of apps and/or models (in the form app_name.model_name) for which metadata will be attached. When an instance is created, a matching metadata instance is automatically created.

Meta.seo_views

List of apps and/or view names to which metadata can be attached. When an app name is given, a urls.py will be used to limit the installed views.

Meta.backends

When you define metadata fields, four django models are created to attach the metadata to various things: paths, model instances, models and views. You can restrict which of these are created by setting backeneds to a list with a subset of the default value: ("path", "modelinstance", "model", "view")

Meta.verbose_name

This is used in the verbose_name for each of the Django models created.

Meta.verbose_name_plural

This is used in the verbose_name_plural for each of the Django models created.

Help Text

Help text for each of the fields can be provided manually, as in Django, but it can also be provided automatically and using a clean bulk-help-text syntax.

Automatic help text

Help text is sometimes automatically generated for fields that do not have an explicit help_text set:

  • When populate_from is set to a literal value, the help text will be set to: 'If empty, "value" will be used.'
  • When populate_from is set to another field, the help text will be set to: 'If empty, other field will be used.'
  • When populate_from is set to a callable, and that callable has an function attribute called short_description, the help text will be set to: 'If empty, short description
Bulk help text

You can also edit the help text for a number of fields in a convenient syntax. For example:

class BasicExample(seo.Metadata):
    title       = seo.Tag(head=True)
    keywords    = seo.MetaTag()
    description = seo.MetaTag()
    heading     = seo.Tag(name="h1")

    class HelpText:
        title  = "This will appear in the window/tab name, as well as in search results."
        keywords = "A comma separated list of words or phrases that describe the content"
        heading = "This will appear in the <h1> element"

Templates

A single template tag is provided to output metadata in templates. It requires loading the seo template library, and can be called in a number of ways:

{% get_metadata %}

This gets the metadata for the current path (if RequestContext is used) and outputs all metadata flagged to appear in the <head>.

{% get_metadata for obj %}

This time, the metadata is retrieved for the path belonging to the given object. The object can be a model instance (actually, anything with get_absolute_url) or a path itself.

{% get_metadata as var %}
{{ var }}

{% get_metadata for obj as var %}
{{ var }}

To exercise a little more flexibility, you can store the retrieved metadata as a context variable. Outputting the variable by itself will output all metadata flagged to appear in the <head>.

If you have multiple metadata definitions, you can choose the relevant one by providing the name of the class. Here are your alternatives for doing so:

{% get_metadata MetadataClass %}
{% get_metadata MetadataClass for obj %}
{% get_metadata MetadataClass as var %}
{% get_metadata MetadataClass for obj as var %}
Metadata template objects

As seen above, you can store the fetched metadata as a variable. This variable can then be used to access specific metadata fields, groups and values. For example:

{{ var }}                   Full output for all metadata flagged to appear in <head>
{{ var.field_name }}        Full output for the given field
{{ var.group_name }}        Full output for all fields in the given group
{{ var.field_name.value }}  Output only the value for the given field

Admin

To add the models of your defined metadata to an admin site, make a single call to register_seo_admin. For example:

from rollyourown.seo.admin import register_seo_admin
from django.contrib import admin
from myapp.seo import MyMetadata

register_seo_admin(admin.site, MyMetadata)

An admin inline can also be created, to add metadata as an inline form on the admin page of a model instance. For example:

from rollyourown.seo.admin import get_inline
from django.contrib import admin
from myapp.seo import MyMetadata

class MyModelAdmin(admin.ModelAdmin):
    inlines = [get_inline(MyMetadata)]

To add an inline for every relevant model registered on an admin site, use the auto_register_inlines function. This function will add inlines for every model listed in seo_models both before and after the function is called.

from rollyourown.seo.admin import auto_register_inlines
from django.contrib import admin
from myapp.seo import MyMetadata

auto_register_inlines(admin.site, MyMetadata)

Note that this is purely for convenience, where the admin site is not customised in any way. It is only for the truly, unashamed lazy. Please, please use get_inlines. The reason is (and I’m not proud of it) that auto_register_inlines does some violent monkey-patching of both the Admin classes in the site’s registry AND the register function of the site itself. It is not a pythonic feature, and I am considering removing it unless there is strong support.

Guide for site administrators

Once the developer has installed the framework, site administrators are able to attach metadata to paths, views, model instances and model classes. Metadata can be added though the four options presented in the admin, under the “Seo” app.

_images/admin-index.png

Sample SEO section from the Django admin index page

Associating Metadata with Paths

The simplest and most flexible way to add metadata is by associating it with a path. Here all you need to do is add the path you want and go for it.

_images/admin-path.png

Sample SEO page to add a new set of path associated metadata

If your metadata is sensitive to sites and languages, you will see these options as well, allowing you to have specific metadata for a given language or site. Leave them blank and it will be the fallback for any language or site.

_images/admin-sites-i18n.png

Sample SEO page with language and site options

Of course, this isn’t the most convenient way to add metadata. You need to know the path in advance, and if it changes, your metadata won’t be used anymore. If your site has thousands of paths, this approach will also consume a healthy amount of your time.

Associating Metadata with Views

Metadata can be assciated with a “view”, even if that view is found on a number of paths. The site developer will choose a number of suitable views, which can be easily selected from a drop down list. Simply choose the appropriate view and the metadata will appear on every relevant path.

_images/admin-view.png

Sample SEO page to add a new set of view associated metadata

Associating Metadata with Model instances

To help make things simpler, metadata can be attached to model instances, for example a particular product. Any time you add a new product, a matching “model instance” metadata will be created automatically. [1] You are then free to add metadata as you please, and any time the path changes, the metadata will follow. The metadata will then appear on the relevant “detail” page for the given instance.

If the site developer has enabled it, metadata can also be directly editable alongside the instance itself. This is convenient when content authors are also responsible for metadata.

_images/admin-modelinstance-inline.png

Sample model instance page with inline metadata

Footnotes

[1]Note that the model needs to be listed in seo_models for this to happen. The site developer will use this to choose which models will automatically create metadata.

Associating Metadata with Models

But of course this won’t help if you have a large number of instances. It is possible to define fallback data for when a field is missing. This means you can define standard metadata and override a particular field or two for a particular model instance.

_images/admin-model.png

Sample SEO page to add a new set of model associated metadata

Integrating Existing Data

Quite often metadata will simply comprise of existing information, such as a product title. It would be mildly inefficient to have to maintain the same information in two separate places, so it is possible to reuse existing information. This can be done in the “Model”, “Model instance” and “View” metadata areas.

If you would like to reference the relevant model instance, you type the name of the model surrounded by two braces. For example Buy {{ product }} today!. You can go further and reference different fields from the relevant instance, for example By {{ product.name }} today!. The syntax is that of the Django template language.

This is particularly useful for the “model” metadata, where fallback values can be customised for all relevant instances.

For “view” metadata, a different set of information is available, depending on the particular view. The site developer will need to let site administrators know which information is available for each view.

Developer Guide

  • Adding new fields (ie KeywordTag)
  • Defining a new backend
  • Data sanitation plugins?

Topical guides

SEO with Django - Best Practices

The following information is not specific to this Django SEO framework, but rather use of SEO with Django in general.

Essential knowledge

Some problems are universal and need to be considered by developers.

Indices, glossary and tables