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 useseo.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
toINSTALLED_APPS
- Make sure
"django.core.context_processors.request"
is listed inTEMPLATE_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.
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 tokeywords
.
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
.
-
head
¶ 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 thehelp_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:- if a callable is provided, call it each time the value is to be displayed
- if name of field or method is provided, use the value provided by that field or method
- 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. ReturnNone
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 aTextField
Django field, thenmax_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 toTrue
, 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
isFalse
.
-
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
isFalse
.
-
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
isFalse
.
-
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 calledshort_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.
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.
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.
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.
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.
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.
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?