Q:

What is the correct way to include subdomains to the Django sitemap urls?

I have my development site (localhost.com 'as on the development machine').
This domain has got two subdomains, developer and blog.
The url configuration for sitemaps are,
from django.contrib.sitemaps.views import sitemap, index as sitemap_index

url(r'^sitemap\.xml$', sitemap_index, {'sitemaps': sitemaps},
    name='django.contrib.sitemaps.views.sitemap'),

url(r'^sitemap-(?P<section>.+)\.xml', sitemap, {'sitemaps': sitemaps}),

when creating sitemaps with sitemap index,
The site maps are created as
<sitemap>
<loc>http://localhost.com/sitemap-blog.xml?p=2</loc>
</sitemap>
<sitemap>
<loc>http://localhost.com/sitemap-blog.xml?p=3</loc>
</sitemap>
<sitemap>
<loc>http://localhost.com/sitemap-blog.xml?p=4</loc>
</sitemap>

I want the sitemap on the subdomain, that is blog.example.com
so I overwrote the index view on django.contrib.sitemap.views by changing the absolute_url to blog.sitemaps as follows
from django.contrib.sitemaps.views import x_robots_tag
from django.contrib.sites.shortcuts import get_current_site
from django.core import urlresolvers
from django.template.response import TemplateResponse

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

    req_protocol = request.scheme
    req_site = get_current_site(request)

    sites = []
    for section, site in sitemaps.items():
        if callable(site):
            site = site()
        protocol = req_protocol if site.protocol is None else site.protocol
        sitemap_url = urlresolvers.reverse(
            sitemap_url_name, kwargs={'section': section})
        absolute_url = '%s://blog.%s%s' % (protocol, req_site.domain, sitemap_url)
        sites.append(absolute_url)
        for page in range(2, site.paginator.num_pages + 1):
            sites.append('%s?p=%s' % (absolute_url, page))

    return TemplateResponse(request, template_name, {'sitemaps': sites},
                            content_type=content_type)

So the output the subdomain index is something like this,
<sitemap>
<loc>http://blog.localhost.com/sitemap-whos.xml?p=3</loc>
</sitemap>
<sitemap>
<loc>http://blog.localhost.com/sitemap-whos.xml?p=4</loc>
</sitemap>

What is the correct way to make django sitemap framework to pick up the dynamic subdomains to the sitemap url?
I use django-subdomains package

A:

Marty!
I've found a great solution for my needs:

No need in django-subdomains, just use  simple middleware taken from here:
class SubdomainMiddleware:
""" Make the subdomain publicly available to classes """

    def process_request(self, request):
        domain_parts = request.get_host().split('.')
        if (len(domain_parts) > 2):
            subdomain = domain_parts[0]
            if (subdomain.lower() == 'www'):
                subdomain = None
            domain = '.'.join(domain_parts[1:])
        else:
            subdomain = None
            domain = request.get_host()

        request.subdomain = subdomain
        request.domain = domain

If you don't use 'sitemap index' alter sitemap view in django.contrib.sitemap.views by adding two variables req_domain and req_subdomain that are now in all requests:

find
    req_protocol = request.scheme
    req_site = get_current_site(request)

add two new lines:
    req_domain = request.domain
    req_subdomain = request.subdomain

then find
    urls.extend(site.get_urls(page=page, site=req_site,
                                  protocol=req_protocol))

and make it look like this:
    urls.extend(site.get_urls(page=page, site=req_site, r_domain=req_domain, 
                                  r_subdomain=req_subdomain, protocol=req_protocol))

Now alter __init__.py in sitemap root dir:

in class Sitemap make get_urls function look like this def get_urls(self, page=1, r_domain=None, r_subdomain=None, site=None, protocol=None)
find th line domain = site.domain, comment it out and add below:
domain = r_domain
subdomain = r_subdomain

now alter this code below:
if getattr(self, 'i18n', False):
        urls = []
        current_lang_code = translation.get_language()
        for lang_code, lang_name in settings.LANGUAGES:
            translation.activate(lang_code)
            urls += self._urls(page, protocol, domain)
        translation.activate(current_lang_code)
    else:
        urls = self._urls(page, protocol, domain)

    return urls

so it looks like this:
if getattr(self, 'i18n', False):
        urls = []
        current_lang_code = translation.get_language()
        for lang_code, lang_name in settings.LANGUAGES:
            translation.activate(lang_code)
            urls += self._urls(page, protocol, domain, subdomain)
        translation.activate(current_lang_code)
    else:
        urls = self._urls(page, protocol, domain, subdomain)

    return urls

find def _urls(self, page, protocol, domain) function below and make it look like this def _urls(self, page, protocol, domain, subdomain)

and in this function below find:
loc = "%s://%s%s" % (protocol, domain, self.__get('location', item))

and replace it with this:
loc = "%s://%s.%s%s" % (protocol, subdomain, domain, self.__get('location', item))

profit!

