【问题标题】:What is the correct way to include subdomains to the Django sitemap urls?将子域包含到 Django 站点地图 url 的正确方法是什么?
【发布时间】:2015-08-06 10:27:49
【问题描述】:

我有我的开发站点(localhost.com '在开发机器上')。

此域有两个子域,developerblog

站点地图的 url 配置是,

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}),

使用站点地图索引创建站点地图时, 站点地图创建为

<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>

我想要子域上的站点地图,即blog.example.com

所以我通过将 absolute_url 更改为 blog.sitemaps 来覆盖 django.contrib.sitemap.views 上的 index 视图,如下所示

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)

所以子域索引的输出是这样的,

<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>

让 django 站点地图框架获取站点地图 url 的动态子域的正确方法是什么?

我使用django-subdomains

【问题讨论】:

    标签: python django sitemap subdomain django-sitemaps


    【解决方案1】:

    马蒂!

    我找到了一个很好的解决方案来满足我的需求:

    1. django-subdomains 中不需要,只需使用取自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
      
    2. 如果您不使用“sitemap index”,则通过添加两个变量 req_domainreq_subdomain,在 django.contrib.sitemap.views 中更改 sitemap 视图,这两个变量现在总共是 requests:

    找到

        req_protocol = request.scheme
        req_site = get_current_site(request)
    

    添加两个新行:

        req_domain = request.domain
        req_subdomain = request.subdomain
    

    然后找到

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

    让它看起来像这样:

        urls.extend(site.get_urls(page=page, site=req_site, r_domain=req_domain, 
                                      r_subdomain=req_subdomain, protocol=req_protocol))
    
    1. 现在在 sitemap 根目录中更改 __init__.py

    class Sitemap 中使get_urls 函数看起来像这样def get_urls(self, page=1, r_domain=None, r_subdomain=None, site=None, protocol=None)

    找到第domain = site.domain行,注释掉并在下面添加:

    domain = r_domain
    subdomain = r_subdomain
    

    现在修改下面的代码:

    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
    

    所以它看起来像这样:

    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
    
    1. 在下面找到def _urls(self, page, protocol, domain)函数,让它看起来像这样def _urls(self, page, protocol, domain, subdomain)

    并在下面的这个函数中找到:

    loc = "%s://%s%s" % (protocol, domain, self.__get('location', item))
    

    并将其替换为:

    loc = "%s://%s.%s%s" % (protocol, subdomain, domain, self.__get('location', item))
    
    1. 利润!

    【讨论】:

      【解决方案2】:

      我的解决方案只扩展了两个类,为带有子域的站点地图创建一组可重用的组件。

      首先我创建了一个新的 SubdomainSite 类来实现django.contrib.sites.models.Site 的接口

      from __future__ import unicode_literals
      
      from django.utils.encoding import python_2_unicode_compatible
      
      
      @python_2_unicode_compatible
      class SubdomainSite(object):
          """
          SubdomainSite shares the interface of Site and adds subdomain support.
          """
          def __init__(self, subdomain, site=None):
              self.subdomain = subdomain
              self.extend_site(site)
      
          def __str__(self):
              return self.domain
      
          def extend_site(self, site):
              """Always returns the root level site extended with subdomain."""
              if issubclass(site.__class__, self.__class__):
                  return self.extend_site(site.root_site)
              elif hasattr(site, 'domain'):
                  self.root_site = site
              self.domain = self.name = '{0}.{1}'.format(self.subdomain, site)
              return self
      
          def save(self, force_insert=False, force_update=False):
              raise NotImplementedError('RequestSite cannot be saved.')
      
          def delete(self):
              raise NotImplementedError('RequestSite cannot be deleted.')
      

      然后与我创建的扩展站点地图的类SubdomainSitemap 一起使用。这个类只添加了一个子域属性,并在get_urls 中添加了两行——它并不像看起来那么复杂,原来的类只是在一个函数中塞进了太多东西。

      from django.contrib.sitemaps import Sitemap
      
      
      class SubdomainSitemap(Sitemap):
          """Adds subdomain support to sitemaps"""
          subdomain = None
      
          def get_urls(self, page=1, site=None, protocol=None):
              """Always uses this sitemap's subdomain if supplied."""
              # Determine protocol
              if self.protocol is not None:
                  protocol = self.protocol
              if protocol is None:
                  protocol = 'http'
      
              # Determine domain
              if site is None and self.subdomain is None:
                  if django_apps.is_installed('django.contrib.sites'):
                      Site = django_apps.get_model('sites.Site')
                      try:
                          site = Site.objects.get_current()
                      except Site.DoesNotExist:
                          pass
                  if site is None:
                      raise ImproperlyConfigured(
                          "To use sitemaps, either enable the sites framework or pass "
                          "a Site/RequestSite object in your view."
                      )
              else:
                  # Setting a subdomain site overrides supplied site
                  site = self.subdomain
              domain = site.domain
      
              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
      

      现在在您的站点地图类中将它们联系在一起!

      from django.contrib.sites.models import Site
      from sitemaps import SubdomainSite, SubdomainSitemap
      from blog.models import Post
      
      current_site = Site.objects.get_current()
      
      
      class BlogSitemap(SubdomainSitemap):
          changefreq = 'monthly'
          subdomain = SubdomainSite('blog', current_site)
          protocol = 'https'
      
          def items(self):
              return Post.objects.all()
      

      瞧!

      【讨论】:

        【解决方案3】:

        对于更通用的All Іѕ Vаиітy 答案,您可以将其用于您可能需要的任何子域:

        class FixedSitemap(Sitemap):
            priority = 0.5
            changefreq = 'monthly'
            protocol = 'https'
        
            def items(self):
                # Add all your items here
                return ['docs.yourdomain.io']
        
            def location(self, obj):
                return obj
        
            def _urls(self, page, protocol, domain):
                return super(FixedSitemap, self)._urls(page, protocol, '')
        

        【讨论】:

          【解决方案4】:

          您可以简单地覆盖站点地图类中的_urls() 方法,并包含一个超级调用,其中域作为子域+主机形式。

          class BlogSitemap(Sitemap):
              def _urls(self, page, protocol, domain):
                  return super(BlogSitemap, self)._urls(
                      page=page, protocol=protocol, domain='docs.djangoproject.com')
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-01-07
            • 2018-03-02
            • 2014-05-22
            • 2019-02-12
            • 2018-04-24
            • 2021-09-24
            • 1970-01-01
            • 2011-08-29
            相关资源
            最近更新 更多