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.