| 1 |
===================== |
|---|
| 2 |
The sitemap framework |
|---|
| 3 |
===================== |
|---|
| 4 |
|
|---|
| 5 |
Django comes with a high-level sitemap-generating framework that makes |
|---|
| 6 |
creating `Google Sitemap`_ XML files easy. |
|---|
| 7 |
|
|---|
| 8 |
.. _Google Sitemap: http://www.google.com/webmasters/sitemaps/docs/en/protocol.html |
|---|
| 9 |
|
|---|
| 10 |
The "sitemap" framework |
|---|
| 11 |
======================= |
|---|
| 12 |
|
|---|
| 13 |
Overview |
|---|
| 14 |
-------- |
|---|
| 15 |
|
|---|
| 16 |
The sitemap-generating framework is based largely off of Django's |
|---|
| 17 |
`syndication framework`_. You tell the framework what you want to include |
|---|
| 18 |
in your sitemap by creating ``Sitemap`` classes and pointing to them |
|---|
| 19 |
in your URLconf_. |
|---|
| 20 |
|
|---|
| 21 |
.. _syndication framework: http://www.djangoproject.com/documentation/syndication/ |
|---|
| 22 |
.. _URLconf: http://www.djangoproject.com/documentation/url_dispatch/ |
|---|
| 23 |
|
|---|
| 24 |
Installation |
|---|
| 25 |
------------ |
|---|
| 26 |
|
|---|
| 27 |
To install the sitemap app, follow these steps: |
|---|
| 28 |
|
|---|
| 29 |
1. Add ``'django.contrib.sitemap'`` to your INSTALLED_APPS_ setting. |
|---|
| 30 |
2. Make sure ``'django.template.loaders.app_directories.load_template_source'`` |
|---|
| 31 |
is in your TEMPLATE_LOADERS_ setting. |
|---|
| 32 |
|
|---|
| 33 |
.. _INSTALLED_APPS: http://www.djangoproject.com/documentation/settings/#installed-apps |
|---|
| 34 |
.. _TEMPLATE_LOADERS: http://www.djangoproject.com/documentation/settings/#template-loaders |
|---|
| 35 |
|
|---|
| 36 |
Initialization |
|---|
| 37 |
-------------- |
|---|
| 38 |
|
|---|
| 39 |
To activate sitemap generation on your Django site, add this line to your |
|---|
| 40 |
URLconf_: |
|---|
| 41 |
|
|---|
| 42 |
( r'^sitemap.xml$', 'django.contrib.sitemap.views.sitemap', {'sitemaps': sitemaps} ) |
|---|
| 43 |
|
|---|
| 44 |
This will tell Django to build a sitemap when a client accesses ``/sitemap.xml``. |
|---|
| 45 |
The name of the sitemap is not important, but the location is. Google will only |
|---|
| 46 |
index links in your sitemap for the current URL level and below. For instance, if |
|---|
| 47 |
``sitemap.xml`` lives in your root directory, it may reference any URL in your |
|---|
| 48 |
site. However, if your sitemap lives at ``/content/sitemap.xml``, it may only |
|---|
| 49 |
reference URLs under ``/content/``. |
|---|
| 50 |
|
|---|
| 51 |
The sitemap view takes an extra argument: ``{'sitemaps': sitemaps}``. ``sitemaps`` |
|---|
| 52 |
should be a dictionary that maps a short section label (i.e. ``blog`` or ``news``) |
|---|
| 53 |
to its ``Sitemap`` class (i.e. ``BlogSitemap`` or ``NewsSitemap``). It may also map |
|---|
| 54 |
to an instance of a ``Sitemap`` class (i.e. ``BlogSitemap(some_var)``). |
|---|
| 55 |
|
|---|
| 56 |
.. _URLconf: http://www.djangoproject.com/documentation/url_dispatch/ |
|---|
| 57 |
|
|---|
| 58 |
Sitemap Classes |
|---|
| 59 |
--------------- |
|---|
| 60 |
|
|---|
| 61 |
A ``Sitemap`` class is a simple python class that represents a "section" of |
|---|
| 62 |
entries in your sitemap. In the simplest case, all these sections get lumped |
|---|
| 63 |
together in one ``sitemap.xml``. It is also possible to use the framework to |
|---|
| 64 |
generate a sitemap index that references individual sitemap files, one per |
|---|
| 65 |
section. |
|---|
| 66 |
|
|---|
| 67 |
``Sitemap`` classes must subclass ``django.contrib.sitemap.Sitemap``. They can |
|---|
| 68 |
live anywhere in your codebase. |
|---|
| 69 |
|
|---|
| 70 |
A simple example |
|---|
| 71 |
---------------- |
|---|
| 72 |
|
|---|
| 73 |
Let's assume you have an ``Entry`` model in your blog, and you want to include |
|---|
| 74 |
all the individual links to your blog entries in your sitemap:: |
|---|
| 75 |
|
|---|
| 76 |
from django.contrib.sitemap import Sitemap |
|---|
| 77 |
from myproject.blog.models import Entry |
|---|
| 78 |
|
|---|
| 79 |
class BlogSitemap(Sitemap): |
|---|
| 80 |
changefreq = "never" |
|---|
| 81 |
priority = 0.5 |
|---|
| 82 |
|
|---|
| 83 |
def items(self): |
|---|
| 84 |
return Entry.objects.filter(is_draft=False) |
|---|
| 85 |
|
|---|
| 86 |
def lastmod(self, obj): |
|---|
| 87 |
return obj.pub_date |
|---|
| 88 |
|
|---|
| 89 |
Note: |
|---|
| 90 |
|
|---|
| 91 |
* ``changefreq`` and ``priority`` are class attributes corresponding to |
|---|
| 92 |
``<changefreq>`` and ``<priority>`` elements, respectively. They could be |
|---|
| 93 |
made callable as functions, as ``lastmod`` was in the example. |
|---|
| 94 |
* ``items()`` is simply a method that returns a list of objects. The objects |
|---|
| 95 |
returned will get passed to any callable methods corresponding to a sitemap |
|---|
| 96 |
property (``location``, ``lastmod``, ``changefreq``, and ``priority``). |
|---|
| 97 |
* ``lastmod`` should return a ``datetime`` object. |
|---|
| 98 |
* There is no ``location`` method. ``Sitemap`` provides a default implementation |
|---|
| 99 |
for you that calls ``get_absolute_url()`` on each object and returns the result. |
|---|
| 100 |
|
|---|
| 101 |
Shortcuts |
|---|
| 102 |
--------- |
|---|
| 103 |
|
|---|
| 104 |
The sitemap framework provides a couple convenience classes for common cases: |
|---|
| 105 |
|
|---|
| 106 |
* FlatpageSitemap |
|---|
| 107 |
* GenericSitemap |
|---|
| 108 |
|
|---|
| 109 |
The ``FlatpageSitemap`` class looks at all flatpages_ defined for the current ``SITE_ID`` |
|---|
| 110 |
(see the sites_ documentation) and creates an entry in the sitemap. These entries include |
|---|
| 111 |
only the ``location`` attribute. |
|---|
| 112 |
|
|---|
| 113 |
The ``GenericSitemap`` class works with any `generic views`_ you already have. To use |
|---|
| 114 |
it, create an instance, passing in the same ``info_dict`` you pass to the |
|---|
| 115 |
generic views. The only requirement is that the dict have a ``queryset`` entry. |
|---|
| 116 |
It may also have a ``date_field`` entry that specifies a date field for objects |
|---|
| 117 |
retrieved from the ``queryset``. This will be used for the ``lastmod`` attribute in |
|---|
| 118 |
the generated sitemap. You may also pass ``priority`` and ``changefreq`` keyword |
|---|
| 119 |
arguments to the ``GenericSitemap`` constructor to specify these attributes for all |
|---|
| 120 |
URLs. |
|---|
| 121 |
|
|---|
| 122 |
Here's an example of a URLconf_ using both:: |
|---|
| 123 |
|
|---|
| 124 |
from django.conf.urls.defaults import * |
|---|
| 125 |
from django.contrib.sitemap import FlatpageSitemap, GenericSitemap |
|---|
| 126 |
from myproject.blog.models import Entry |
|---|
| 127 |
|
|---|
| 128 |
info_dict = { |
|---|
| 129 |
'queryset': Entry.objects.all(), |
|---|
| 130 |
'date_field': 'pub_date', |
|---|
| 131 |
} |
|---|
| 132 |
|
|---|
| 133 |
sitemaps = { |
|---|
| 134 |
'flatpages': FlatpageSitemap, |
|---|
| 135 |
'blog': GenericSitemap(info_dict, priority=0.6), |
|---|
| 136 |
} |
|---|
| 137 |
|
|---|
| 138 |
urlpatterns = patterns('', |
|---|
| 139 |
# ... some generic view using info_dict |
|---|
| 140 |
( r'^sitemap.xml$', 'django.contrib.sitemap.views.sitemap', {'sitemaps': sitemaps} ) |
|---|
| 141 |
) |
|---|
| 142 |
|
|---|
| 143 |
.. _flatpages: http://www.djangoproject.com/documentation/flatpages/ |
|---|
| 144 |
.. _sites: http://www.djangoproject.com/documentation/sites/ |
|---|
| 145 |
.. _generic views: http://www.djangoproject.com/documentation/generic_views/ |
|---|
| 146 |
.. _URLconf: http://www.djangoproject.com/documentation/url_dispatch/ |
|---|
| 147 |
|
|---|
| 148 |
Creating a sitemap index |
|---|
| 149 |
------------------------ |
|---|
| 150 |
|
|---|
| 151 |
The sitemap framework also has the ability to create a sitemap index |
|---|
| 152 |
that references individual sitemap files, one per each section defined |
|---|
| 153 |
in your ``sitemaps`` dict. The only differences in usage are: |
|---|
| 154 |
|
|---|
| 155 |
* You use two views in your URLconf: ``django.contrib.sitemap.views.index`` |
|---|
| 156 |
and ``django.contrib.sitemap.views.sitemap`` |
|---|
| 157 |
* The ``django.contrib.sitemap.views.sitemap`` view should take a |
|---|
| 158 |
``section`` keyword argument. |
|---|
| 159 |
|
|---|
| 160 |
Here is what the relevant URLconf lines would look like for the example above:: |
|---|
| 161 |
|
|---|
| 162 |
( r'^sitemap.xml$', 'django.contrib.sitemap.views.index', {'sitemaps': sitemaps} ) |
|---|
| 163 |
( r'^sitemap-(?P<section>.+).xml$', 'django.contrib.sitemap.views.sitemap', {'sitemaps': sitemaps} ) |
|---|
| 164 |
|
|---|
| 165 |
This will automatically generate a ``sitemap.xml`` file that references |
|---|
| 166 |
both ``sitemap-flatpages.xml`` and ``sitemap-blog.xml``. The ``Sitemap`` |
|---|
| 167 |
classes and the ``sitemaps`` dict don't change at all. |
|---|
| 168 |
|
|---|
| 169 |
Pinging Google |
|---|
| 170 |
-------------- |
|---|
| 171 |
|
|---|
| 172 |
For sites with dynamic content, it may be desirable to "ping" Google when |
|---|
| 173 |
your sitemap changes, to let them know to re-index your site. The framework |
|---|
| 174 |
provides a function to do just that: ``ping_google()``. This will automatically |
|---|
| 175 |
determine your sitemap URL and send a ping to Google. |
|---|
| 176 |
|
|---|
| 177 |
One useful way to call ``ping_google()`` is from a model's ``save()`` method:: |
|---|
| 178 |
|
|---|
| 179 |
from django.contrib.sitemap import ping_google |
|---|
| 180 |
|
|---|
| 181 |
def save(self): |
|---|
| 182 |
super(Entry, self).save() |
|---|
| 183 |
try: |
|---|
| 184 |
ping_google() |
|---|
| 185 |
except: |
|---|
| 186 |
pass |
|---|
| 187 |
|
|---|
| 188 |
A more efficient solution, however, would be to call ``ping_google()`` from a |
|---|
| 189 |
cron script, or some other scheduled task. |
|---|