Django Sitemap Framework. Accepting query parameters

1.3k views Asked by At

I'm using the Django Sitemap Framework

I've no problem retrieving a list of articles from my DB.

class ArticleSitemap(Sitemap):
    def items(self):
        return articles.objects.filter(tagid=1399).order_by('-publisheddate')

I now want to accept a query parameter to filter by an inputted tag id ie:

sitemap.xml?tagid=1000

I have yet to find an example in the docs or on stack.

2

There are 2 answers

1
user508402 On

Its in the request's Get-attribute:

the url '.../names/getNames?pattern=Helm' results in a request-object that has as GET : <QueryDict: {'pattern': ['Helm']}>

1
illagrenan On

It is not possible to access HttpRequest object from Sitemap class. Probably the easiest way is to create your own view(s) for the sitemap(s), do what you need to do with HttpRequest and call Django internal view to do the final rendering of XML.

Setup your sitemap URLs as Django docs says (https://docs.djangoproject.com/en/dev/ref/contrib/sitemaps/#initialization), but use your own view(s).

urls.py:

from my_app.sitemap_views import custom_sitemap_index, custom_sitemap_section

sitemaps = {
    "foo": FooSitemap,
    "bar": BarSitemap,
}

urlpatterns = [
    url(
        r"^sitemap\.xml$",
        custom_sitemap_index,
        {"sitemaps": sitemaps},
        name="sitemap_index",
    ),
    url(
        r"^sitemap-(?P<section>.+)\.xml$",
        custom_sitemap_section,
        {"sitemaps": sitemaps},
        name="sitemaps",
    ),
    # ...
]

Your custom sitemap views are standard Django views: you can access HttpRequest, database, cache...

sitemap_views.py:

import copy

from django.contrib.sitemaps import views as django_sitemaps_views
from django.contrib.sitemaps.views import x_robots_tag


@x_robots_tag
def custom_sitemap_index(
    request,
    sitemaps,
    template_name="sitemap_index.xml",
    content_type="application/xml",
    sitemap_url_name="django.contrib.sitemaps.views.sitemap",
):
    print("You can access request here.", request)

    return django_sitemaps_views.index(
        request, template_name, content_type, sitemaps, sitemap_url_name
    )


@x_robots_tag
def custom_sitemap_section(
    request,
    sitemaps,
    section=None,
    template_name="sitemap.xml",
    content_type="application/xml",
):
    tag_id = int(request.GET.get("tagid"))

    # We do not want to modify global variable "sitemaps"!
    # Otherwise sitemap instances would be shared across requests (tag_id should be dynamic).
    sitemaps_copy = copy.deepcopy(sitemaps)

    for section, site in sitemaps_copy.items():
        if callable(site):
            sitemaps_copy[section] = site(tag_id=tag_id)

    return django_sitemaps_views.sitemap(
        request, sitemaps_copy, section, template_name, content_type
    )

sitemap.py:

from django.contrib.sitemaps import Sitemap


class FooSitemap(Sitemap):
    def __init__(self, tag_id: int):
        self.tag_id = tag_id
        super().__init__()

    def items(self):
        return (
            Articles.objects.filter(tagid=1399)
            .filter(tag_id=self.tag_id)
            .order_by("-publisheddate")
        )


class BarSitemap(Sitemap):
    pass
    # ...
    # ...