Django Sitemap Index Tutorial

Von 6. November 2015Tutorial, Web & App

Hat man seine Webseite mit dem Django Framework entwickelt, gibt es eine Vielzahl von Möglichkeiten zur Erstellung von Sitemaps. Leider sind nicht alle Möglichkeiten gut dokumentiert, vor allem, wenn man eine Blog-Seite oder ein Online Magazin betreibt. Ständig neuer Content soll so schnell/bequem wie möglich an die Öffentlichkeit gebracht werden. Da dies nicht ganz so trivial ist, widmen wir dem Thema ein eigenes Tutorial. Unser Django Sitemap Index Tutorial behandelt folgende Anforderungen:

  • Vollautomatische Updates der Sitemaps bei neuen und geänderten Blog/News Einträgen
  • Automatische Content Notifications an Google News
  • Automatische Content Notifications an Google Search Console
  • Sitemap Index mit unterschiedlichen Sitemap Templates
  • Bilder Sitemaps

Django Sitemap Index – Die Basics

Eine Minimalkonfiguration für eine Sitemap mit Django in zwei Schritten.

1. Schritt:
Bereiten Sie Ihre settings.py Datei auf Sitemaps vor. Stellen Sie dazu sicher, dass sich „sites“ und „sitemaps“ unter den installierten Apps befinden.

#settings.py INSTALLED_APPS = ( .... 'django.contrib.sites', 'django.contrib.sitemaps', ...., )

2. Schritt:
Fügen Sie Ihrer „urls.py“ Datei eine Sitemap hinzu:

#urls.py from django.contrib.sitemaps import Sitemap from django.conf.urls import patterns, url from beispielapp import views import django.contrib.sitemaps.views as vi   #hier stehen die urlpatterns ihrer Seite urlpatterns = patterns('', url(r'^$', views.startseite, name='index'), url(r'^news/$', views.news, name='news'), url(r'^impressum/$', views.impressum, name='impressum'), )   #basic sitemap mit den Name der URLs definieren basic_sitemap = { 'pages':Sitemap(['index', 'news','impressum']) } #die sitemap zu den url patterns hinzufügen urlpatterns += patterns('', (r'^sitemap.xml$', vi.sitemap, {'sitemaps': basic_sitemaps}), )

SEO-tauglicher Django Sitemap Index

Im vorherigen Abschnitt haben wir eine einfache Sitemap mit Django erstellt. So weit so gut. Nun fangen die Probleme an.

Dynamische URLs:

Die meisten Django Seiten nutzen URL Parameter – in unserem Beispiel ist die News Seite voll mit durchnummerierten News-Artikeln. Wir wollen nun für alle News-Artikel automatisch einen Sitemap Eintrag generieren, um nicht jedesmal bei einem neuen Eintrag die Sitemap anzupassen. Dazu erweitern wir die Uripatterns um eine dynamische „newsdetail“ Url:

#urls.py ... urlpatterns = patterns('', url(r'^$', views.startseite, name='index'), url(r'^news/$', views.news, name='news'), url(r'^impressum/$', views.impressum, name='impressum'), url(r'^news/id=(?<pk>\d+)/$', views.newsdetail, name="newsdetail"), ) ...

Der dazugehörige View baut auf unserem „Newsletters“ Model auf. Wir definieren einen Newsletter View auf Basis unseres Newsletter-Templates „detail.html“ (Templates in Django erstellen siehe Django-Tutorial Teil 3).

#views.py from django.http.response import Http404 from django.shortcuts import render from beispielapp.models import Newsletters ... def newsdetail(request, pk=None): try: article = Newsletters.objects.get(article_id=pk) except article.DoesNotExist: article = None raise Http404("Article does not exist") return render(request, 'news/detail.html', {'article': articles})

Ein Beispiel Template für den newsdetail view könnte so aussehen:

#detail.html {% extends "base.html" %} {% block content %} {% load staticfiles %} {% if article %} <h1>{{ article.headline }}</h1> {{ article.content }} <a href="{% url 'news' %}">Zur Newsletter Übersicht</a> {% endif %} {% endblock %}

Das Newsletters Model benutzt die Methode „get_absolute_url()“, um seine URL der Sitemap zur Verfügung zu stellen. Die Methode „get_id()“ stellt sicher, dass ein neuer Newsletter immer eine höhere id erhält als ein alter. Nachdem unsere Webseite bei Google Search Console indiziert wurde, wollen wir jedes Update automatisch an Google schicken. Aus SEO Sicht hilft uns das, schneller an Relevanz zu gewinnen. Dazu fügen wir in der „save“ Funktion den Befehl „ping_google()“ hinzu, der jedesmal Google anpingt, wenn eine Änderung abgespeichert wird.

#models.py from datetime import datetime from django.db import models from django.core.urlresolvers import reverse from django.contrib.sitemaps import ping_google   class Newsletters(models.Model):   def get_id(): number = Newsletters.objects.last().article_id if number == None: return 1 else: return number + 1   article_id = models.IntegerField(db_column='article_ID', primary_key=True,default=get_id) headline = models.CharField(max_length=255, blank=True,default="") content = models.TextField(blank=True,default='Content') date = models.DateTimeField(default=datetime.now,blank=True, null=True) def __unicode__(self): return u'%s' % (self.headline)   def get_absolute_url(self): return reverse('newsdetail', kwargs={'pk':self.article_id})   class Meta: managed = False db_table = 'newsletters'   def save(self, force_insert=False, force_update=False): super(Newsletters, self).save(force_insert, force_update) try: ping_google() except Exception: pass

Für dieses Model wollen wir nun eine dynamische Sitemap erstellen, die URL Parameter akzeptiert. Wir legen dazu eine Datei „sitemaps.py“ in unserem Beispielapp Verzeichnis an und erstellen eine Newsletter Sitemap. Die Sitemap soll wöchentlich gecrawlt werden. Hierfür initialisieren wir den Parameter changefreq = ‚weekly‘. Das letzte Update eines Newsletters teilen wir der Sitemap in der Methode „lastmod“ mit: der Parameter „obj“ steht hier für das zuvor definierte Model. In „lastmod“ übermitteln wir der Sitemap, das im Model definierte, DateTimeField „date“.

#sitemaps.py from django.core.urlresolvers import reverse from django.contrib import sitemaps import datetime from beispielapp.models import Newsletters   class NewsletterSitemap(sitemaps.Sitemap): changefreq = 'weekly' priority = 0.5   def items(self): return Newsletters.objects.all()   def lastmod(self, obj): return obj.date

Nun registrieren wir unsere NewsletterSitemap in urls.py:

#urls.py ... from beispielapp.sitemaps import NewsletterSitemap ...   #Newsletter Sitemap erzeugen newsletter_sitemaps={ 'newslettersitemap': NewsletterSitemap }   #die sitemap zu den url patterns hinzufügen urlpatterns += patterns('', url(r'^newsletter_sitemap.xml$', vi.sitemap, {'sitemaps': newsletter_sitemaps, 'template_name': 'newsletter_sitemap.html', }, name='newslettersitemap'), )

Was noch fehlt ist das Template „newsletter_sitemap.html“. In diesem bauen wir nun unsere Listung als Google News Seite ein, um weiter an Relevanz für SEO zu gewinnen.

#newsletter_sitemap.html <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"> {% spaceless %} {% for url in urlset %} <url> <loc>{{ url.location }}</loc> {% if url.item.lastmod %}<lastmod>{{ url.item.lastmod|date:"Y-m-d" }}</lastmod>{% endif %} {% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %} {% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %} <news:news> <news:publication> <news:name>beispielapp.com</news:name> <news:language>de</news:language> </news:publication>   <news:genres>PressRelease</news:genres> {% if url.item.headline %}<news:title>{{ url.item.headline }}</news:title>{% endif %} {% if url.item.date %}<news:publication_date>{{ url.item.date|date:"Y-m-d" }}</news:publication_date>{% endif %} </news:news> </url> {% endfor %} {% endspaceless %} </urlset>

Wir haben nun eine SEO optimierte Newsletter Sitemap mit automatischem Update und Notification Funktion an die Google Search Console und an Google News. Was nun noch fehlt – die Newsletter Sitemap mit unserer statischen Sitemap zu vereinen.

Mehrere Sitemaps zusammenführen

Etwas vorweg: es gibt in der offiziellen Django Dokumentation eine Index Funktion Django Sitemap Index. Mit dieser lassen sich hierarchische XML Sitemaps erstellen. Die nehmen wir nun her und passen Sie so an, dass sie auch mit Templates umgehen kann. Die Sitemaps werden im Django Sitemap Index gebündelt. Um ein Sitemap Bündel zu erstellen, fügen wir unsere Sitmaps in das basic_sitemap Dictionary ein.

#urls.py from beispielapp.sitemaps import NewsletterSitemap ... #basic sitemap mit den Name der URLs und Link zur Newsletter Sitemap basic_sitemap = { 'pages':Sitemap(['index', 'news','impressum','newslettersitemap']), 'newslettersitemap': NewsletterSitemap }   #die sitemap zu den url patterns hinzufügen urlpatterns += patterns('', (r'^sitemap.xml$', vi.index, {'sitemaps': basic_sitemap}), (r'^sitemap-(?P<section>.+)\.xml$', vi.sitemap, {'sitemaps': basic_sitemap}), )

Bilder Sitemaps:

Was uns jetzt noch fehlt sind Bilder, die wir bei der Google Search Console gelistet haben wollen. Hierzu erstellen wir ein Newsletter-Image Model, das auf den dazugehörigen Newsletter Eintrag verweist. Wichtig ist hier, dass man bei der Methode „get_absolute_url“ die Adresse des Newsletters angibt, um den in der Image Sitemaps Definition richtig zu setzen. Dazu definieren wir ein „ForeignKey“ Feld, das den Verweis auf den zugehörigen Newsletter beinhaltet.

#models.py ... class NewsletterImages(models.Model):   def lastArticle(): no = Newsletters.objects.last() return no   image = models.FileField(upload_to=content_file_name,storage=fs,blank=True) image_id = models.IntegerField(db_column='image_ID', primary_key=True,default=lastArticle) article = models.ForeignKey(Newsletters, db_column='article_id') name = models.CharField(max_length=50, blank=True)   def __unicode__(self): return u'%s' % (self.name)   #Die url des dazugehörigen Newsletter Eintrags def get_absolute_url(self): return reverse('newsdetail', kwargs={'pk':self.article.article_id})   class Meta: managed = False db_table = 'newsletter_images'

Zum Model generieren wir eine passendes Sitemap Template „newsletterimage_sitemap.html“, indem sowohl der Verweis auf die beinhaltende Seite ( Tag) als auch auf das Bild selbst ( Tag) steht.

#newsletterimage_sitemap.html <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"> {% spaceless %} {% for url in urlset %} <url> <loc> {{ url.location }} </loc> <image:image> <image:loc> {{ MEDIA_URL }}images/{{ url.item.name }}.jpg </image:loc> <image:title> {{ url.item.name }} <image:title> </image:image> </url> {% endfor %} {% endspaceless %} </urlset>

Wir fügen nun auf Basis des NewsletterImage Models eine weitere Sitemap zu sitemaps.py hinzu:

#sitemaps.py from startseite.models import NewsletterImages ... class NewsletterImageSitemap(sitemaps.Sitemap): changefreq = 'weekly' priority = 0.5   def items(self): return NewsletterImages.objects.all()   def lastmod(self, obj): return obj.date

Abschließend registrieren wir unsere NewsletterImage Sitemap noch in urls.py:

#urls.py from beispielapp.sitemaps import NewsletterImageSitemap ... #basic sitemap mit den Name der URLs und Link zur Newsletter Sitemap basic_sitemap = { 'pages':Sitemap(['index','news','impressum']), 'newslettersitemap': NewsletterSitemap, 'newslettersimageitemap': NewsletterImageSitemap, ...

Nun haben wir das Problem, dass wir zwar einen Sitemap Index haben, aber noch immer Custom Templates für die einzelnen Sitemaps. Um den Django Sitemap Index um Templates zu erweitern ersetzen wir nun die Sections durch unsere Templates:

#urls.py ... urlpatterns += patterns('', (r'^sitemap.xml$', vi.index, {'sitemaps': basic_sitemap}), #(r'^sitemap-(?P<section>.+)\.xml$', vi.sitemap, {'sitemaps': basic_sitemap}), (r'^sitemap-pages.xml$', vi.sitemap,{'sitemaps': pages_sitemaps,'section':'pages'}), url(r'^sitemap-newslettersitemap\.xml$', vi.sitemap, { 'sitemaps': newsletter_sitemaps, 'section':'newslettersitemap', 'template_name': 'news_sitemap.html', },name='newssitemap'), url(r'^sitemap-newslettersimagesitemap\.xml$', vi.sitemap, { 'sitemaps': image_sitemaps, 'section':'newslettersimagesitemap', 'template_name': 'newsletterimage_sitemap.html' },name='imagesitemap'), )

Beim Aufruf von „www.beispielapp.com/sitemap.xml“ sollte nun eine Liste in diesem Stil erscheinen:

<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <sitemap> <loc>http://beispielapp.com/sitemap-newslettersitemap.xml</loc> </sitemap> <sitemap> <loc>http://beispielapp.com/sitemap-pages.xml</loc> </sitemap> <sitemap> <loc>http://beispielapp.com/sitemap-newsletterimagesitemap.xml</loc> </sitemap> </sitemapindex>

Reichen Sie nun Ihre Sitemap bei Google Search Console ein.

Kommentar hinterlassen