İçeriğe geç

Django Sitemaps

Merhabalar.

Modern web uygulamalarının hayati parçalarından biri, arama motorlarının sayfanızı indexleyebilmesini ve SEO puanını yükselterek daha fazla göz önünüze çıkmasını ve trafiğini yükseltmesini sağlayan XML formatında sitemaplerdir. Bu haritalar ile arama motorları uygulamanız üzerinde hangi urllerin yaşadığını, kırılım yaşamadan ulaşılabilen derinliklerini, hangi aralıklarla güncellendiği ve index önem sırası gibi bilgileri dinamik olarak saptar ve uygulamanızı indexler.

Örnek bir sitemap -> https://www.egehangundogdu.com/post-sitemap.xml

Şanslıyız ki Django yerleşik olarak yukarıdaki işlemlerde kullanılacak olan site haritalarını oluşturmak için yerleşik bir uygulamaya sahip!

Bugün gerekli sitemapleri oluşturmayı ve konfigüre etmeye, basit bir blog projesi üzerinden adım adım göz atacağız. Hazırsanız başlayalım.


Başlamadan önce hızlıca temiz bir venv oluşturalım, bağımlılıkları yükleyelim, Django projemizi ve appimizi oluşturalım.

$ virtualenv -p python3 venv
$ source venv/bin/activate
$ pip install django ipython
$ django-admin startproject my_project . && ./manage.py startapp posts

Daha sonra yeni posts appini kaydededlim.

# my_project/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'posts',
]

Daha sonra blog projemizde gönderilerimizi tutacak basit modeli hazırlayalım.

#posts/models.py

from django.db import models
from django.urls import reverse


class Post(models.Model):

    title = models.CharField(max_length=255)
    content = models.TextField()
    slug = models.SlugField(unique=True)

    def __str__(self) -> str:
        return self.title

    def get_absolute_url(self):
        return reverse("posts:post-detail", kwargs={"slug": self.slug})

Gerekli migrationları oluşturalım ve değişiklikleri veritabanına uygulayalım.

$ python manage.py makemigrations && python manage.py migrate

Bir kaç gönderi oluşturmamız gerekmekte, admin panelini kullanarak bu işlemi halledelim.

Modeli admin paneline kaydetmek için;

#posts/admin.py
from django.contrib import admin
from posts.models import Post

@admin.register(Post)
class PostModelAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

Bu işlemden sonra bir superuser, ardından admin panelinde bir kaç gönderi oluşturabilirsiniz.

$ python manage.py createsuperuser

post-admin-exampleBir kaç gönderi daha oluşturalım.

Sitemapler hem statik sayfalar (cookie-kullanım, hakkımızda vs) hem de model nesnelerinin listeleme, detay gibi sayfalarını içerebilir.

Basitçe 2 adet statik sayfa oluşturalım. Temel seviyede bir proje olduğundan herhangi bir appe bağlı olmadan direkt proje dizininde views.py oluşturabilirsiniz.

#my_project/views.py

from django.http import HttpResponse
from django.views import View


class AboutView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("About page.")

class CookiePolicyView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("CookiePolicy page.")

Hızlıca gönderilerimiz için, gerekli detay viewini ve templateini de oluşturalım.

posts/views.py

from django.views.generic import DetailView
from posts.models import Post


class PostDetailView(DetailView):
    model = Post

Dikkat etti iseniz, bir template name vermedik, generic viewlar template name verilmediğinde aşağıdaki şemaya göre gerekli templatei arar ve render eder. #tips

<app_label>/<model_name>_<template_name_suffix>.html

TEMPLATES settingsde DIRS arrayını “templates” yolunu ekledikten sonra gerekli templatei oluşturalım. (Proje dizininde bir template hiyerarşisi oluşturacağız.)

templates/posts/post_detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{object.title}}</title>
</head>
<body>
    <div>
        {{object.content}}
    </div>
</body>
</html>

Tamam görünüyor. Urllere viewlarımızı bağlayalım.

# my_project.urls.py

from django.urls import include, path
from my_project.views import AboutView, CookiePolicyView
from django.contrib import admin

urlpatterns = [
    path("admin/", admin.site.urls),
    path("cookie-policy/", CookiePolicyView.as_view(), name="cookie-policy"),
    path("about/", AboutView.as_view(), name="about"),
    path("posts/", include("posts.urls")),
]
# posts/urls.py

from django.urls import path
from posts.views import PostDetailView

app_name = "posts"

urlpatterns = [
    path("detail/<slug:slug>/", PostDetailView.as_view(), name="post-detail"),
]
$ http --body :2345/cookie-policy/ 
CookiePolicy page.

$ http --body :2345/about/        
About page.

Böylelikle genel yapıyı oturttuk ve elimizde sitemap üzerine konulabilecek dinamik sayfalar ve statik sayfalar bulunuyor!


Sitemap Framework Kurulum.

Sitemapler oluşturmak için sitemap ve sites frameworklerini içeriye dahil etmemiz gerekmekte.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sitemaps',
    'django.contrib.sites',
    'posts',
]

SITE_ID = 1

Daha sonrasında tek bir site sunduğumuzu varsayarak SITE_ID değerini belirtiyoruz. Esasen sitemap frameworkü db bağımlıklarına sahip olmasa da sites framework db bağımlılıklarına sahip ve projeniz üzerinde yönetilmekte olan siteleri tutmak ve bir takım özellikler ile bağdaştırmakla yükümlü. Bundan dolayı gerekli migrationu veritabanına yazıyoruz;

$ python manage.py migrate

Statik sayfalar için sitemap oluşturmak.

Sitemap frameworkü, gerekli sitemap xmlleri oluşturmak için Sitemap sınıfını sunuyor. Sitemap sınıfı üzerinde yapılacak değişiklikler ile sitemapin özelliklerini değiştirebiliyor (örneğin önem derecesi, hangi protokol üzerinden gerekli urli dönecegi veya degisme sıklığı), dahil edilecek olan urlleri sınırlayabiliyoruz.

Proje dizinimizde statik sayfaların sitemapini oluşturmak için sitemaps.py adlı bir dosya oluşturalım.

# my_project/sitemaps.py

from django.contrib.sitemaps import Sitemap
from django.urls import reverse

class StaticPagesSitemap(Sitemap):

    changefreq = "monthly"
    priorty = 0.6
    
    def items(self):
        return ["about", "cookie-policy"]

    def location(self, item):
        return reverse(item)

Sitemap sınıfını miras alan bir sınıf oluşturuyoruz. Burada genellikle tanımlanan 2 metod bulunuyor. Bu metodlar, items ve location.

Items esasen iterable dönmesi beklenen bir metod. Bu iterable bir queryset olabilecegi gibi yukarıdaki örnekte görülebileceği üzere ilgili urlleri tutan bir named views listesi de olabilir.

location metodu ise sitemape eklenecek olan itemin projeniz üzerindeki absolute urlini geri dönmekle görevli.  items metodunun döndüğü iterable içerisinde tanımlı olan her item için çalıştırılır.

changefreq ve priority arama motorlarının indexleme sırasındaki davranışlarını yönetir. İlki olan changefreq bu sitemap üzerinde bulunacak olan itemların ne sıklıkla güncellendiği konusunda arama motorunu bilgilendirir. Yerleşik olarak aşağıdaki değerleri alabilir;

  • <span class="pre">'always'</span>
  • <span class="pre">'hourly'</span>
  • <span class="pre">'daily'</span>
  • <span class="pre">'weekly'</span>
  • <span class="pre">'monthly'</span>
  • <span class="pre">'yearly'</span>
  • <span class="pre">'never'</span>

priorty ise sitemap protokolü için anlamlı olup, ilgili sitemapteki itemların ve dolayısıyla urllerin indexlenme sırasındaki önem sırasını belirler. 0 ile 1.0 arasında float bir değer alır. Daha detaylı bilgi almak isterseniz.

Bunun yanında languages, i18n, limit gibi değerler yine sitemap sınıfında tanımlı ve kullanılabilecek olan diğer attributelardır. Örneğin i18n aktif edilirse projenizde tanımlı olan tüm diller için urller generate edilecektir.

Statik sayfalar için belirli kurallar içeren sitemapimizi oluşturduk. Şimdi sunma vakti!

Bu işlem için sitemap frameworkünde bulunan viewi kullanacağız.

my_project/urls.py

from django.contrib.sitemaps import views as sitemaps_views
from my_project.sitemaps import StaticPagesSitemap


sitemaps = {"static_pages": StaticPagesSitemap}
urlpatterns = [
    path("admin/", admin.site.urls),
    path(
        "sitemap.xml", sitemaps_views.sitemap, {"sitemaps": sitemaps}, name="sitemaps"
    ),
    path("cookie-policy/", CookiePolicyView.as_view(), name="cookie-policy"),
    path("about/", AboutView.as_view(), name="about"),
    path("posts/", include("posts.urls")),
]

proje dizinindeki url şeması bu şekilde. sitemaps viewi kwargs üzerinden sitemaps adlı bir dict kabul edecek, tanımlı sitemap sınıflarını teker teker işleyecek ve gerekli sitemapi oluşturacaktır.

Dinamik sayfalar için sitemapler oluşturmak.

Aslında ilk adımda yaptığımız işlemden çok da farklı bir şey yapmayacağız. Fakat bu örnekle items ve location metodları arasındaki bağlantıyı iyice kavrayacağımızı düşünüyorum.

Gönderilerimiz için bir sitemap sınıfı oluşturacak olursak;

# posts/sitemaps.py

from django.contrib.sitemaps import Sitemap
from posts.models import Post


class PostSiteMap(Sitemap):
    changefreq = "weekly"
    priority = 0.9
    def items(self):
        return Post.objects.all()

    def location(self, obj: Post) -> str:
        return obj.get_absolute_url()

Items bir qs dönüyor ve qs içindeki her nesne için modelde tanımlı olan ve Django için önemli olan get_absolute_url metodunu çağırıyoruz. Yeni sitemapi de sitemaps sozlugune ekleyelim ve gönderilerimiz gerekli yapının oluşup oluşmadığını kontrol edelim.

get_absolute_url metodu hakkında daha detaylı bilgi almak isterseniz.

Proje dizinindeki urls dosyasındaki aşağıdaki değişikliği gerçekleştirerek işe başlayalım.

from posts.sitemap import PostSiteMap

sitemaps = {"static_pages": StaticPagesSitemap, "posts_sitemap": PostSiteMap}

Gönderilerimizde artık sitemapin bir parçası. Harika!

Url adresinde example.com görmenizin sebebi Django sites frameworkünü içeriye ilk dahil ettiğiniz anda bu adda bir site oluşturuyor. Daha sonrasında eğer frameworkü kullanacaksanız, hostnameiniz ile değiştirmeniz gerekiyor.

Şu aşamaya kadar aslında Django ile bir sitemapin nasıl oluşturabileceğini ve metodlar arasındaki bağlantıyı fazlasıyla kavradığımızı düşünüyorum fakat çok fazla sayıda urlin barındığı bir projede (örneğin e ticaret) takılacağımız bir limitleme bulunuyor.

Sitemapler 50.000 item ile sınırlandırılmıştır.

Bu durumu aşmanın ise bir yolu var. Projenizin fazla sayıda url barındıran komponentlerini ayrı sitemaplerden indexlenmesi için sunmak.

Büyük komponentlerin sitemaplerini ayrık sunmak.

Bu işlemde fazlasıyla kolay ve yine Django’nun bize sunduğu sitemap index view üzerinden bu süreci yöneteceğiz.

Proje dizinindeki urls.py dosyasında urlpatternsi aşağıdaki hale getirip üstüne konuşalım.

sitemaps = {"static": StaticPagesSitemap, "posts": PostSiteMap}

urlpatterns = [
    path("admin/", admin.site.urls),
    path(
        "sitemap.xml",
        sitemaps_views.index,
        {"sitemaps": sitemaps, "sitemap_url_name": "sitemaps"},
        name="sitemap-index",
    ),
    path(
        "sitemap-<section>.xml",
        sitemaps_views.sitemap,
        {"sitemaps": sitemaps},
        name="sitemaps",
    ),
    path("about/", AboutView.as_view(), name="about"),
    path("cookie-policy/", CookiePolicyView.as_view(), name="cookie-policy"),
    path("posts/", include("posts.urls")),
]

Artık birden fazla sitemapi ayrık olarak sunacağız. Dolayısıyla ilk olarak bir index oluşturacağız. Bu index sayfası altında yaşayan sitemap urllerini dönecek ve arama motorları bu adresler üzerinden tanımlı olan sitemapleri takip ederek indexleme yapacak.

section ve sitemap_url_name yine özel argümanlar. Sitemaps sözlügünde tanımlı olan keyleri kullanarak ilgili sitemapin ayrık urlini oluşturmakla görevli. Bu oluşturma işlemi sırasında da ilgili named viewsi çağırmak için sitemap_url_name tanımlandı.

Sitemap Index sayfasına gidecek olursak;

artık ayrık yönetebiliyoruz. Arama motorları bu itemlar üstünde kırılımlanacak ve indexleme işlemlerini gerçekleştirecektir.


Sonuç.

SEO açısından sitemapler oldukça kritik bir konu. Arama motorları tarafından iyi indexlenen bir web uygulaması, daha fazla kullanıcıya ulaşacak sitenizin popülerliğini ve gelirini yukarıya çekecektir.

Django’nun yerleşik olarak yukarıdaki probleme nasıl bir cevap önerdiğini artık biliyoruz. (Biraz fazla detaylı olmuş olabilir 🙂 )

Uzun ve keyifli bir yazı oldu açıkcası bu konuyu yazayım derken bu kadar uzayacağını düşünmemiştim. Umarım keyif almış ve bu yazıyı işe yarar bulmuşsunuzdur.

Görüşmek üzere!

 

 

Tarih:Blog

İlk Yorumu Siz Yapın

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Göster
Gizle