Fixed #22782 -- Added i18n attr to Sitemap class

It makes possible to have your sitemap in multiple languages when
using i18n in URLs.
This commit is contained in:
Luan Pablo 2014-06-06 15:47:15 -03:00 committed by Tim Graham
parent 78c32f1caa
commit 407d070329
7 changed files with 75 additions and 2 deletions

View File

@ -484,6 +484,7 @@ answer newbie questions, and generally made Django that much better:
Christian Oudard <christian.oudard@gmail.com> Christian Oudard <christian.oudard@gmail.com>
oggie rob <oz.robharvey@gmail.com> oggie rob <oz.robharvey@gmail.com>
oggy <ognjen.maric@gmail.com> oggy <ognjen.maric@gmail.com>
Luan Pablo <luanpab@gmail.com>
Tomek Paczkowski <tomek@hauru.eu> Tomek Paczkowski <tomek@hauru.eu>
Jens Page Jens Page
Guillaume Pannatier <guillaume.pannatier@gmail.com> Guillaume Pannatier <guillaume.pannatier@gmail.com>

View File

@ -1,6 +1,8 @@
from django.apps import apps as django_apps from django.apps import apps as django_apps
from django.conf import settings
from django.core import urlresolvers, paginator from django.core import urlresolvers, paginator
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils import translation
from django.utils.six.moves.urllib.parse import urlencode from django.utils.six.moves.urllib.parse import urlencode
from django.utils.six.moves.urllib.request import urlopen from django.utils.six.moves.urllib.request import urlopen
@ -89,6 +91,19 @@ class Sitemap(object):
raise ImproperlyConfigured("To use sitemaps, either enable the sites framework or pass a Site/RequestSite object in your view.") raise ImproperlyConfigured("To use sitemaps, either enable the sites framework or pass a Site/RequestSite object in your view.")
domain = site.domain 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
def _urls(self, page, protocol, domain):
urls = [] urls = []
latest_lastmod = None latest_lastmod = None
all_items_lastmod = True # track if all items have a lastmod all_items_lastmod = True # track if all items have a lastmod

View File

@ -1,5 +1,6 @@
from django.apps import apps from django.apps import apps
from django.core.cache import cache from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
@ -17,6 +18,16 @@ class TestModel(models.Model):
return '/testmodel/%s/' % self.id return '/testmodel/%s/' % self.id
class I18nTestModel(models.Model):
name = models.CharField(max_length=100)
class Meta:
app_label = 'sitemaps'
def get_absolute_url(self):
return reverse('i18n_testmodel', args=[self.id])
@override_settings(ROOT_URLCONF='django.contrib.sitemaps.tests.urls.http') @override_settings(ROOT_URLCONF='django.contrib.sitemaps.tests.urls.http')
class SitemapTestsBase(TestCase): class SitemapTestsBase(TestCase):
protocol = 'http' protocol = 'http'
@ -28,3 +39,4 @@ class SitemapTestsBase(TestCase):
cache.clear() cache.clear()
# Create an object for sitemap content. # Create an object for sitemap content.
TestModel.objects.create(name='Test Object') TestModel.objects.create(name='Test Object')
I18nTestModel.objects.create(name='Test Object')

View File

@ -171,3 +171,14 @@ class HTTPSitemapTests(SitemapTestsBase):
def test_empty_sitemap(self): def test_empty_sitemap(self):
response = self.client.get('/empty/sitemap.xml') response = self.client.get('/empty/sitemap.xml')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@override_settings(LANGUAGES=(('en', 'English'), ('pt', 'Portuguese')))
def test_simple_i18nsitemap_index(self):
"A simple i18n sitemap index can be rendered"
response = self.client.get('/simple/i18n.xml')
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>{0}/en/i18n/testmodel/1/</loc><changefreq>never</changefreq><priority>0.5</priority></url><url><loc>{0}/pt/i18n/testmodel/1/</loc><changefreq>never</changefreq><priority>0.5</priority></url>
</urlset>
""".format(self.base_url)
self.assertXMLEqual(response.content.decode('utf-8'), expected_content)

View File

@ -1,9 +1,11 @@
from datetime import datetime from datetime import datetime
from django.conf.urls import url from django.conf.urls import url
from django.conf.urls.i18n import i18n_patterns
from django.contrib.sitemaps import Sitemap, GenericSitemap, FlatPageSitemap, views from django.contrib.sitemaps import Sitemap, GenericSitemap, FlatPageSitemap, views
from django.http import HttpResponse
from django.views.decorators.cache import cache_page from django.views.decorators.cache import cache_page
from django.contrib.sitemaps.tests.base import TestModel from django.contrib.sitemaps.tests.base import I18nTestModel, TestModel
class SimpleSitemap(Sitemap): class SimpleSitemap(Sitemap):
@ -16,6 +18,15 @@ class SimpleSitemap(Sitemap):
return [object()] return [object()]
class SimpleI18nSitemap(Sitemap):
changefreq = "never"
priority = 0.5
i18n = True
def items(self):
return I18nTestModel.objects.all()
class EmptySitemap(Sitemap): class EmptySitemap(Sitemap):
changefreq = "never" changefreq = "never"
priority = 0.5 priority = 0.5
@ -42,10 +53,18 @@ class FixedLastmodMixedSitemap(Sitemap):
return [o1, o2] return [o1, o2]
def testmodelview(request, id):
return HttpResponse()
simple_sitemaps = { simple_sitemaps = {
'simple': SimpleSitemap, 'simple': SimpleSitemap,
} }
simple_i18nsitemaps = {
'simple': SimpleI18nSitemap,
}
empty_sitemaps = { empty_sitemaps = {
'empty': EmptySitemap, 'empty': EmptySitemap,
} }
@ -74,6 +93,7 @@ urlpatterns = [
url(r'^simple/sitemap-(?P<section>.+)\.xml$', views.sitemap, url(r'^simple/sitemap-(?P<section>.+)\.xml$', views.sitemap,
{'sitemaps': simple_sitemaps}, name='django.contrib.sitemaps.views.sitemap'), {'sitemaps': simple_sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
url(r'^simple/sitemap\.xml$', views.sitemap, {'sitemaps': simple_sitemaps}), url(r'^simple/sitemap\.xml$', views.sitemap, {'sitemaps': simple_sitemaps}),
url(r'^simple/i18n\.xml$', views.sitemap, {'sitemaps': simple_i18nsitemaps}),
url(r'^simple/custom-sitemap\.xml$', views.sitemap, url(r'^simple/custom-sitemap\.xml$', views.sitemap,
{'sitemaps': simple_sitemaps, 'template_name': 'custom_sitemap.xml'}), {'sitemaps': simple_sitemaps, 'template_name': 'custom_sitemap.xml'}),
url(r'^empty/sitemap\.xml$', views.sitemap, {'sitemaps': empty_sitemaps}), url(r'^empty/sitemap\.xml$', views.sitemap, {'sitemaps': empty_sitemaps}),
@ -86,3 +106,7 @@ urlpatterns = [
url(r'^cached/sitemap-(?P<section>.+)\.xml', cache_page(1)(views.sitemap), url(r'^cached/sitemap-(?P<section>.+)\.xml', cache_page(1)(views.sitemap),
{'sitemaps': simple_sitemaps}, name='cached_sitemap') {'sitemaps': simple_sitemaps}, name='cached_sitemap')
] ]
urlpatterns += i18n_patterns(
url(r'^i18n/testmodel/(?P<id>\d+)/$', testmodelview, name='i18n_testmodel'),
)

View File

@ -232,6 +232,15 @@ Sitemap class reference
sitemap was requested is used. If the sitemap is built outside the sitemap was requested is used. If the sitemap is built outside the
context of a request, the default is ``'http'``. context of a request, the default is ``'http'``.
.. attribute:: Sitemap.i18n
.. versionadded:: 1.8
**Optional.**
A boolean attribute that defines if the URLs of this sitemap should
be generated using all of your :setting:`LANGUAGES`. The default is
``False``.
Shortcuts Shortcuts
========= =========

View File

@ -83,7 +83,8 @@ Minor features
:mod:`django.contrib.sitemaps` :mod:`django.contrib.sitemaps`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* ... * The new :attr:`Sitemap.i18n <django.contrib.sitemaps.Sitemap.i18n>` attribute
allows you to generate a sitemap based on the :setting:`LANGUAGES` setting.
:mod:`django.contrib.sites` :mod:`django.contrib.sites`
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^