網站地圖框架

Django 內建高階網站地圖產生框架,用以建立 網站地圖 XML 檔案。

概觀

網站地圖是您網站上的一個 XML 檔案,它會告知搜尋引擎索引器您的頁面變更頻率,以及某些頁面相對於您網站上其他頁面的「重要性」。此資訊有助於搜尋引擎索引您的網站。

Django 網站地圖框架可讓您使用 Python 程式碼表示此資訊,藉此自動化建立此 XML 檔案的流程。

它的運作方式很像 Django 的 聯合饋送框架。若要建立網站地圖,請撰寫 Sitemap 類別,並在您的 URLconf 中指向它。

安裝

若要安裝網站地圖應用程式,請依照下列步驟進行

  1. 'django.contrib.sitemaps' 新增至您的 INSTALLED_APPS 設定。

  2. 請確認您的 TEMPLATES 設定包含一個 DjangoTemplates 後端,其 APP_DIRS 選項設定為 True。它預設會在那裡,因此如果您已變更該設定,您才需要變更此設定。

  3. 請確認您已安裝 網站 框架

(注意:網站地圖應用程式不會安裝任何資料庫表格。它之所以需要進入 INSTALLED_APPS 的唯一原因是,Loader() 範本載入器可以找到預設範本。)

初始化

views.sitemap(request, sitemaps, section=None, template_name='sitemap.xml', content_type='application/xml')

若要在您的 Django 網站上啟用網站地圖產生功能,請將此行新增至您的 URLconf

from django.contrib.sitemaps.views import sitemap

path(
    "sitemap.xml",
    sitemap,
    {"sitemaps": sitemaps},
    name="django.contrib.sitemaps.views.sitemap",
)

這會告知 Django,當用戶端存取 /sitemap.xml 時,建立網站地圖。

網站地圖檔案的名稱並不重要,但位置很重要。搜尋引擎只會索引您網站地圖中目前 URL 層級及以下的連結。例如,如果 sitemap.xml 位於您的根目錄中,則它可以參考您網站中的任何 URL。但是,如果您的網站地圖位於 /content/sitemap.xml,則它只能參考以 /content/ 開頭的 URL。

網站地圖檢視會採用一個額外的必要引數:{'sitemaps': sitemaps}sitemaps 應該是一個字典,它會將簡短的區段標籤 (例如,blognews) 對應到其 Sitemap 類別 (例如,BlogSitemapNewsSitemap)。它也可以對應到 Sitemap 類別的執行個體 (例如,BlogSitemap(some_var))。

Sitemap 類別

Sitemap 類別是 Python 類別,代表您網站地圖中項目的「區段」。例如,一個 Sitemap 類別可以代表您網誌的所有項目,而另一個類別可以代表您行事曆中的所有活動。

在最簡單的情況下,所有這些區段都會被歸在一起到一個 sitemap.xml 中,但也可能使用該框架產生一個網站地圖索引,該索引會參考個別的網站地圖檔案,每個區段一個。(請參閱下方的 建立網站地圖索引。)

Sitemap 類別必須子類別化 django.contrib.sitemaps.Sitemap。它們可以位於您程式碼庫中的任何位置。

範例

假設您有一個網誌系統,其中包含 Entry 模型,並且您希望您的網站地圖包含所有指向您個別網誌項目的連結。以下是您的網站地圖類別的外觀

from django.contrib.sitemaps import Sitemap
from blog.models import Entry


class BlogSitemap(Sitemap):
    changefreq = "never"
    priority = 0.5

    def items(self):
        return Entry.objects.filter(is_draft=False)

    def lastmod(self, obj):
        return obj.pub_date

注意

  • changefreqpriority 是對應於 <changefreq><priority> 元素的類別屬性。它們可以變成可呼叫的函式,就像範例中的 lastmod 一樣。

  • items() 是一種方法,會傳回物件的 序列QuerySet。傳回的物件將會傳遞至對應於網站地圖屬性的任何可呼叫的方法 (locationlastmodchangefreqpriority)。

  • lastmod 應該傳回 datetime

  • 在此範例中沒有 location 方法,但您可以提供它以指定您的物件的 URL。預設情況下,location() 會在每個物件上呼叫 get_absolute_url() 並傳回結果。

Sitemap 類別參考

class Sitemap[原始碼]

一個 Sitemap 類別可以定義以下方法/屬性:

items[原始碼]

必要。 一個方法,會回傳一個物件的序列QuerySet。框架不在意這些物件的類型;重要的是這些物件會被傳遞到 location()lastmod()changefreq()priority() 方法。

location[原始碼]

選用。 可以是方法或屬性。

如果它是方法,它應該回傳由 items() 回傳的給定物件的絕對路徑。

如果它是屬性,它的值應該是一個字串,表示要用於 items() 回傳的每個物件的絕對路徑。

在這兩種情況下,「絕對路徑」指的是不包含協定或網域的 URL。範例:

  • 正確: '/foo/bar/'

  • 錯誤: 'example.com/foo/bar/'

  • 錯誤: 'https://example.com/foo/bar/'

如果沒有提供 location,框架會對 items() 回傳的每個物件呼叫 get_absolute_url() 方法。

若要指定 'http' 以外的協定,請使用 protocol

lastmod

選用。 可以是方法或屬性。

如果它是方法,它應該接收一個參數,即由 items() 回傳的物件,並以 datetime 的形式回傳該物件的最後修改日期/時間。

如果它是屬性,它的值應該是一個 datetime,表示 items() 回傳的每個物件的最後修改日期/時間。

如果網站地圖中的所有項目都有 lastmod,則由 views.sitemap() 產生的網站地圖將會有一個 Last-Modified 標頭,其值等於最新的 lastmod。你可以啟用 ConditionalGetMiddleware 以使 Django 適當地回應包含 If-Modified-Since 標頭的要求,這將防止在網站地圖沒有變更時傳送網站地圖。

paginator[原始碼]

選用。

此屬性回傳 Paginatoritems()。 如果你分批產生網站地圖,你可能需要將其覆寫為快取的屬性,以避免多次呼叫 items()

changefreq

選用。 可以是方法或屬性。

如果它是方法,它應該接收一個參數,即由 items() 回傳的物件,並以字串的形式回傳該物件的變更頻率。

如果它是屬性,它的值應該是一個字串,表示 items() 回傳的每個物件的變更頻率。

無論你使用方法還是屬性,changefreq 可能的值為:

  • 'always'

  • 'hourly'

  • 'daily'

  • 'weekly'

  • 'monthly'

  • 'yearly'

  • 'never'

priority

選用。 可以是方法或屬性。

如果它是方法,它應該接收一個參數,即由 items() 回傳的物件,並以字串或浮點數的形式回傳該物件的優先順序。

如果它是屬性,它的值應該是一個字串或浮點數,表示 items() 回傳的每個物件的優先順序。

priority 的範例值:0.4, 1.0。頁面的預設優先順序為 0.5。有關更多資訊,請參閱 sitemaps.org 文件

protocol

選用。

此屬性定義網站地圖中 URL 的協定 ('http''https')。如果未設定,則使用請求網站地圖的協定。如果網站地圖是在請求上下文之外建立的,則預設為 'https'

在 Django 5.0 中變更

在較舊的版本中,在請求上下文之外建立的網站地圖的預設協定為 'http'

limit

選用。

此屬性定義網站地圖的每個頁面中包含的 URL 的最大數量。其值不應超過 50000 的預設值,這是 網站地圖協定中允許的上限。

i18n

選用。

一個布林值屬性,定義是否應使用所有 LANGUAGES 來產生此網站地圖的 URL。預設值為 False

languages

選用。

一個 序列語言代碼,用於在啟用 i18n 時產生替代連結。預設值為 LANGUAGES

alternates

選用。

一個布林值屬性。當與 i18n 結合使用時,產生的每個 URL 都會有一份替代連結清單,使用 hreflang 屬性指向其他語言版本。預設值為 False

x_default

選用。

一個布林值屬性。當 True 時,由 alternates 產生的替代連結將包含一個 hreflang="x-default" 後備項目,其值為 LANGUAGE_CODE。預設值為 False

get_latest_lastmod()[原始碼]

可選的。 一個方法,回傳由 lastmod 回傳的最新值。此函數用於將 lastmod 屬性添加到 網站地圖索引上下文變數 中。

預設情況下,get_latest_lastmod() 會回傳

  • 如果 lastmod 是一個屬性:lastmod

  • 如果 lastmod 是一個方法:呼叫該方法並帶入由 Sitemap.items() 回傳的所有項目後,回傳的最新的 lastmod 值。

get_languages_for_item(item)[原始碼]

可選的。 一個方法,回傳顯示該項目的語言代碼序列。預設情況下,get_languages_for_item() 會回傳 languages

快捷方式

網站地圖框架為常見情況提供了一個便利的類別

class GenericSitemap(info_dict, priority=None, changefreq=None, protocol=None)[原始碼]

django.contrib.sitemaps.GenericSitemap 類別允許您透過傳遞一個字典來建立網站地圖,該字典必須至少包含一個 queryset 條目。此 queryset 將用於產生網站地圖的項目。它也可能有一個 date_field 條目,指定從 queryset 檢索的物件的日期欄位。這將用於 lastmod 屬性和產生的網站地圖中的 get_latest_lastmod() 方法。

prioritychangefreqprotocol 關鍵字引數允許為所有 URL 指定這些屬性。

範例

以下是使用 GenericSitemapURLconf 範例

from django.contrib.sitemaps import GenericSitemap
from django.contrib.sitemaps.views import sitemap
from django.urls import path
from blog.models import Entry

info_dict = {
    "queryset": Entry.objects.all(),
    "date_field": "pub_date",
}

urlpatterns = [
    # some generic view using info_dict
    # ...
    # the sitemap
    path(
        "sitemap.xml",
        sitemap,
        {"sitemaps": {"blog": GenericSitemap(info_dict, priority=0.6)}},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

靜態視圖的網站地圖

您通常會希望搜尋引擎爬蟲索引既非物件詳細資訊頁面也非平面頁面的視圖。解決方案是在 items 中明確列出這些視圖的 URL 名稱,並在網站地圖的 location 方法中呼叫 reverse()。例如

# sitemaps.py
from django.contrib import sitemaps
from django.urls import reverse


class StaticViewSitemap(sitemaps.Sitemap):
    priority = 0.5
    changefreq = "daily"

    def items(self):
        return ["main", "about", "license"]

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


# urls.py
from django.contrib.sitemaps.views import sitemap
from django.urls import path

from .sitemaps import StaticViewSitemap
from . import views

sitemaps = {
    "static": StaticViewSitemap,
}

urlpatterns = [
    path("", views.main, name="main"),
    path("about/", views.about, name="about"),
    path("license/", views.license, name="license"),
    # ...
    path(
        "sitemap.xml",
        sitemap,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

建立網站地圖索引

views.index(request, sitemaps, template_name='sitemap_index.xml', content_type='application/xml', sitemap_url_name='django.contrib.sitemaps.views.sitemap')

網站地圖框架還具有建立網站地圖索引的功能,該索引會參考個別的網站地圖檔案,每個檔案對應您 sitemaps 字典中定義的每個區段。使用上的唯一區別是

以下是上述範例的相關 URLconf 行

from django.contrib.sitemaps import views

urlpatterns = [
    path(
        "sitemap.xml",
        views.index,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.index",
    ),
    path(
        "sitemap-<section>.xml",
        views.sitemap,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

這將自動產生一個 sitemap.xml 檔案,其中會參考 sitemap-flatpages.xmlsitemap-blog.xmlSitemap 類別和 sitemaps 字典完全不會變更。

如果所有網站地圖都有由 Sitemap.get_latest_lastmod() 回傳的 lastmod,則網站地圖索引將會有一個等於最新 lastmodLast-Modified 標頭。

如果您的其中一個網站地圖的 URL 超過 50,000 個,您應該建立索引檔案。在這種情況下,Django 會自動對網站地圖進行分頁,而索引會反映這一點。

如果您未使用預設的網站地圖視圖 – 例如,如果它使用快取裝飾器包裝 – 您必須命名您的網站地圖視圖,並將 sitemap_url_name 傳遞到索引視圖

from django.contrib.sitemaps import views as sitemaps_views
from django.views.decorators.cache import cache_page

urlpatterns = [
    path(
        "sitemap.xml",
        cache_page(86400)(sitemaps_views.index),
        {"sitemaps": sitemaps, "sitemap_url_name": "sitemaps"},
    ),
    path(
        "sitemap-<section>.xml",
        cache_page(86400)(sitemaps_views.sitemap),
        {"sitemaps": sitemaps},
        name="sitemaps",
    ),
]

範本客製化

如果您希望為您網站上提供的每個網站地圖或網站地圖索引使用不同的範本,您可以使用 URLconf 將 template_name 參數傳遞給 sitemapindex 視圖來指定它

from django.contrib.sitemaps import views

urlpatterns = [
    path(
        "custom-sitemap.xml",
        views.index,
        {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
        name="django.contrib.sitemaps.views.index",
    ),
    path(
        "custom-sitemap-<section>.xml",
        views.sitemap,
        {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

這些視圖會回傳 TemplateResponse 實例,讓您可以輕鬆自訂轉譯前的回應資料。如需更多詳細資訊,請參閱 TemplateResponse 文件

上下文變數

當您為 index()sitemap() 視圖自訂範本時,您可以依賴以下上下文變數。

索引

變數 sitemaps 是一個物件列表,其中包含每個網站地圖的 locationlastmod 屬性。每個 URL 都會公開以下屬性

  • location: 網站地圖的位置(網址和頁面)。

  • lastmod: 由每個網站地圖的 get_latest_lastmod() 方法填入。

網站地圖

變數 urlset 是一個應該出現在網站地圖中的 URL 列表。每個 URL 都會公開 Sitemap 類別中定義的屬性

  • alternates

  • changefreq

  • item

  • lastmod

  • location

  • priority

當啟用 i18nalternates 時,alternates 屬性才可用。它是一個包含其他語言版本的列表,包括每個 URL 的可選 x_default 回退。每個替代版本都是一個字典,其中包含 locationlang_code 鍵。

每個 URL 都加入了 item 屬性,以允許更靈活地自訂範本,例如 Google 新聞網站地圖。假設 Sitemap 的 items() 會傳回一個包含 publication_datatags 欄位的項目列表,如下所示將會產生一個與 Google 新聞相容的網站地圖

<?xml version="1.0" encoding="UTF-8"?>
<urlset
  xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
  xmlns:news="https://www.google.com/schemas/sitemap-news/0.9">
{% spaceless %}
{% for url in urlset %}
  <url>
    <loc>{{ url.location }}</loc>
    {% if url.lastmod %}<lastmod>{{ url.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>
      {% if url.item.publication_date %}<news:publication_date>{{ url.item.publication_date|date:"Y-m-d" }}</news:publication_date>{% endif %}
      {% if url.item.tags %}<news:keywords>{{ url.item.tags }}</news:keywords>{% endif %}
    </news:news>
   </url>
{% endfor %}
{% endspaceless %}
</urlset>
返回頂端