Fixed #34688 -- Removed contrib.sitemaps.ping_google() and ping_google management command.

Thanks Joachim Jablon for the report.

Google has deprecated the sitemap ping endpoint, and will be removing
it in 6 months ~January 2024.
This commit is contained in:
Andrew Northall 2023-07-02 21:48:56 +01:00 committed by Mariusz Felisiak
parent 2584783f46
commit 6d427288e4
13 changed files with 12 additions and 259 deletions

View File

@ -1,60 +1,9 @@
from urllib.parse import urlencode
from urllib.request import urlopen
from django.apps import apps as django_apps
from django.conf import settings
from django.core import paginator
from django.core.exceptions import ImproperlyConfigured
from django.urls import NoReverseMatch, reverse
from django.utils import translation
PING_URL = "https://www.google.com/webmasters/tools/ping"
class SitemapNotFound(Exception):
pass
def ping_google(sitemap_url=None, ping_url=PING_URL, sitemap_uses_https=True):
"""
Alert Google that the sitemap for the current site has been updated.
If sitemap_url is provided, it should be an absolute path to the sitemap
for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this
function will attempt to deduce it by using urls.reverse().
"""
sitemap_full_url = _get_sitemap_full_url(sitemap_url, sitemap_uses_https)
params = urlencode({"sitemap": sitemap_full_url})
urlopen("%s?%s" % (ping_url, params))
def _get_sitemap_full_url(sitemap_url, sitemap_uses_https=True):
if not django_apps.is_installed("django.contrib.sites"):
raise ImproperlyConfigured(
"ping_google requires django.contrib.sites, which isn't installed."
)
if sitemap_url is None:
try:
# First, try to get the "index" sitemap URL.
sitemap_url = reverse("django.contrib.sitemaps.views.index")
except NoReverseMatch:
try:
# Next, try for the "global" sitemap URL.
sitemap_url = reverse("django.contrib.sitemaps.views.sitemap")
except NoReverseMatch:
pass
if sitemap_url is None:
raise SitemapNotFound(
"You didn't provide a sitemap_url, and the sitemap URL couldn't be "
"auto-detected."
)
Site = django_apps.get_model("sites.Site")
current_site = Site.objects.get_current()
scheme = "https" if sitemap_uses_https else "http"
return "%s://%s%s" % (scheme, current_site.domain, sitemap_url)
class Sitemap:
# This limit is defined by Google. See the index documentation at

View File

@ -1,16 +0,0 @@
from django.contrib.sitemaps import ping_google
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "Ping Google with an updated sitemap, pass optional url of sitemap"
def add_arguments(self, parser):
parser.add_argument("sitemap_url", nargs="?")
parser.add_argument("--sitemap-uses-http", action="store_true")
def handle(self, *args, **options):
ping_google(
sitemap_url=options["sitemap_url"],
sitemap_uses_https=not options["sitemap_uses_http"],
)

View File

@ -588,78 +588,3 @@ generate a Google News compatible sitemap:
</urlset>
.. _`Google news sitemaps`: https://support.google.com/news/publisher-center/answer/9606710
Pinging Google
==============
You may want to "ping" Google when your sitemap changes, to let it know to
reindex your site. The sitemaps framework provides a function to do just
that: :func:`django.contrib.sitemaps.ping_google()`.
.. function:: ping_google(sitemap_url=None, ping_url=PING_URL, sitemap_uses_https=True)
``ping_google`` takes these optional arguments:
* ``sitemap_url`` - The absolute path to your site's sitemap (e.g.,
:file:`'/sitemap.xml'`).
If this argument isn't provided, ``ping_google`` will perform a reverse
lookup in your URLconf, for URLs named
``'django.contrib.sitemaps.views.index'`` and then
``'django.contrib.sitemaps.views.sitemap'`` (without further arguments) to
automatically determine the sitemap URL.
* ``ping_url`` - Defaults to Google's Ping Tool:
https://www.google.com/webmasters/tools/ping.
* ``sitemap_uses_https`` - Set to ``False`` if your site uses ``http``
rather than ``https``.
:func:`ping_google` raises the exception
``django.contrib.sitemaps.SitemapNotFound`` if it cannot determine your
sitemap URL.
.. admonition:: Register with Google first!
The :func:`ping_google` command only works if you have registered your
site with `Google Search Console`_.
.. _`Google Search Console`: https://search.google.com/search-console/welcome
One useful way to call :func:`ping_google` is from a model's ``save()``
method::
from django.contrib.sitemaps import ping_google
class Entry(models.Model):
# ...
def save(self, force_insert=False, force_update=False):
super().save(force_insert, force_update)
try:
ping_google()
except Exception:
# Bare 'except' because we could get a variety
# of HTTP-related exceptions.
pass
A more efficient solution, however, would be to call :func:`ping_google` from a
cron script, or some other scheduled task. The function makes an HTTP request
to Google's servers, so you may not want to introduce that network overhead
each time you call ``save()``.
Pinging Google via ``manage.py``
--------------------------------
.. django-admin:: ping_google [sitemap_url]
Once the sitemaps application is added to your project, you may also
ping Google using the ``ping_google`` management command:
.. code-block:: shell
python manage.py ping_google [/sitemap.xml]
.. django-admin-option:: --sitemap-uses-http
Use this option if your sitemap uses ``http`` rather than ``https``.

View File

@ -1759,18 +1759,6 @@ documentation.
Can be run as a cron job or directly to clean out expired sessions.
``django.contrib.sitemaps``
---------------------------
``ping_google``
~~~~~~~~~~~~~~~
This command is only available if the :doc:`Sitemaps framework
</ref/contrib/sitemaps>` (``django.contrib.sitemaps``) is installed.
Please refer to its :djadmin:`description <ping_google>` in the Sitemaps
documentation.
``django.contrib.staticfiles``
------------------------------

View File

@ -455,10 +455,10 @@ Miscellaneous
passed as a value to encode because ``None`` can't be encoded in GET and POST
data. Either pass an empty string or omit the value.
* The :djadmin:`ping_google` management command now defaults to ``https``
* The ``ping_google`` management command now defaults to ``https``
instead of ``http`` for the sitemap's URL. If your site uses http, use the
new :option:`ping_google --sitemap-uses-http` option. If you use the
:func:`~django.contrib.sitemaps.ping_google` function, set the new
new ``ping_google --sitemap-uses-http`` option. If you use the
``django.contrib.sitemaps.ping_google`` function, set the new
``sitemap_uses_https`` argument to ``False``.
* :djadmin:`runserver` no longer supports ``pyinotify`` (replaced by Watchman).

View File

@ -443,6 +443,15 @@ backends.
* Support for GEOS 3.6 and 3.7 is removed.
:mod:`django.contrib.sitemaps`
------------------------------
* The ``django.contrib.sitemaps.ping_google()`` function and the
``ping_google`` management command are removed as the Google
Sitemaps ping endpoint is deprecated and will be removed in January 2024.
* The ``django.contrib.sitemaps.SitemapNotFound`` exception class is removed.
Using ``create_defaults__exact`` may now be required with ``QuerySet.update_or_create()``
-----------------------------------------------------------------------------------------

View File

@ -1,18 +0,0 @@
from unittest import mock
from django.core.management import call_command
from .base import SitemapTestsBase
@mock.patch("django.contrib.sitemaps.management.commands.ping_google.ping_google")
class PingGoogleTests(SitemapTestsBase):
def test_default(self, ping_google_func):
call_command("ping_google")
ping_google_func.assert_called_with(sitemap_url=None, sitemap_uses_https=True)
def test_args(self, ping_google_func):
call_command("ping_google", "foo.xml", "--sitemap-uses-http")
ping_google_func.assert_called_with(
sitemap_url="foo.xml", sitemap_uses_https=False
)

View File

@ -1,59 +0,0 @@
from unittest import mock
from urllib.parse import urlencode
from django.contrib.sitemaps import SitemapNotFound, _get_sitemap_full_url, ping_google
from django.core.exceptions import ImproperlyConfigured
from django.test import modify_settings, override_settings
from .base import SitemapTestsBase
class PingGoogleTests(SitemapTestsBase):
@override_settings(ROOT_URLCONF="sitemaps_tests.urls.sitemap_only")
@mock.patch("django.contrib.sitemaps.urlopen")
def test_something(self, urlopen):
ping_google()
params = urlencode(
{"sitemap": "https://example.com/sitemap-without-entries/sitemap.xml"}
)
full_url = "https://www.google.com/webmasters/tools/ping?%s" % params
urlopen.assert_called_with(full_url)
@override_settings(ROOT_URLCONF="sitemaps_tests.urls.sitemap_only")
def test_get_sitemap_full_url_global(self):
self.assertEqual(
_get_sitemap_full_url(None),
"https://example.com/sitemap-without-entries/sitemap.xml",
)
@override_settings(ROOT_URLCONF="sitemaps_tests.urls.index_only")
def test_get_sitemap_full_url_index(self):
self.assertEqual(
_get_sitemap_full_url(None), "https://example.com/simple/index.xml"
)
@override_settings(ROOT_URLCONF="sitemaps_tests.urls.empty")
def test_get_sitemap_full_url_not_detected(self):
msg = (
"You didn't provide a sitemap_url, and the sitemap URL couldn't be "
"auto-detected."
)
with self.assertRaisesMessage(SitemapNotFound, msg):
_get_sitemap_full_url(None)
def test_get_sitemap_full_url_exact_url(self):
self.assertEqual(
_get_sitemap_full_url("/foo.xml"), "https://example.com/foo.xml"
)
def test_get_sitemap_full_url_insecure(self):
self.assertEqual(
_get_sitemap_full_url("/foo.xml", sitemap_uses_https=False),
"http://example.com/foo.xml",
)
@modify_settings(INSTALLED_APPS={"remove": "django.contrib.sites"})
def test_get_sitemap_full_url_no_sites(self):
msg = "ping_google requires django.contrib.sites, which isn't installed."
with self.assertRaisesMessage(ImproperlyConfigured, msg):
_get_sitemap_full_url(None)

View File

@ -1 +0,0 @@
urlpatterns = []

View File

@ -1,13 +0,0 @@
from django.contrib.sitemaps import views
from django.urls import path
from .http import simple_sitemaps
urlpatterns = [
path(
"simple/index.xml",
views.index,
{"sitemaps": simple_sitemaps},
name="django.contrib.sitemaps.views.index",
),
]

View File

@ -1,11 +0,0 @@
from django.contrib.sitemaps import views
from django.urls import path
urlpatterns = [
path(
"sitemap-without-entries/sitemap.xml",
views.sitemap,
{"sitemaps": {}},
name="django.contrib.sitemaps.views.sitemap",
),
]