Allow deleting the default locale (#6553)

Fixes #6533
pull/6565/head
Matt Westcott 2020-11-16 14:30:32 +00:00
rodzic 414571cc99
commit 9ef3685efc
5 zmienionych plików z 114 dodań i 4 usunięć

Wyświetl plik

@ -15,6 +15,7 @@ Changelog
* Fix: Handle `get_supported_language_variant` returning a language variant not in `LANGUAGES` (Matt Westcott)
* Fix: Reinstate missing icon on settings edit view (Jérôme Lebleu)
* Fix: Avoid performance and pagination logic issues with a large number of languages (Karl Hobley)
* Fix: Allow deleting the default locale (Matt Westcott)
2.11.1 (06.11.2020)

Wyświetl plik

@ -18,3 +18,4 @@ Bug fixes
* Handle ``get_supported_language_variant`` returning a language variant not in ``LANGUAGES`` (Matt Westcott)
* Reinstate missing icon on settings edit view (Jérôme Lebleu)
* Avoid performance and pagination logic issues with a large number of languages (Karl Hobley)
* Allow deleting the default locale (Matt Westcott)

Wyświetl plik

@ -373,6 +373,26 @@ class Locale(models.Model):
except (cls.DoesNotExist, LookupError):
return cls.get_default()
@transaction.atomic
def delete(self, *args, **kwargs):
# if we're deleting the locale used on the root page node, reassign that to a new locale first
root_page_with_this_locale = Page.objects.filter(depth=1, locale=self)
if root_page_with_this_locale.exists():
# Select the default locale, if one exists and isn't the one being deleted
try:
new_locale = Locale.get_default()
default_locale_is_ok = (new_locale != self)
except (Locale.DoesNotExist, LookupError):
default_locale_is_ok = False
if not default_locale_is_ok:
# fall back on any remaining locale
new_locale = Locale.all_objects.exclude(pk=self.pk).first()
root_page_with_this_locale.update(locale=new_locale)
return super().delete(*args, **kwargs)
def language_code_is_valid(self):
return self.language_code in get_content_languages()

Wyświetl plik

@ -1,8 +1,8 @@
from django.contrib.messages import get_messages
from django.test import TestCase
from django.test import TestCase, override_settings
from django.urls import reverse
from wagtail.core.models import Locale
from wagtail.core.models import Locale, Page
from wagtail.tests.utils import WagtailTestUtils
@ -175,6 +175,10 @@ class TestLocaleDeleteView(TestCase, WagtailTestUtils):
self.assertFalse(Locale.objects.filter(language_code='fr').exists())
def test_cannot_delete_locales_with_pages(self):
# create a French locale so that the deletion is not rejected on grounds of being the only
# existing locale
Locale.objects.create(language_code='fr')
response = self.post()
self.assertEqual(response.status_code, 200)
@ -186,3 +190,76 @@ class TestLocaleDeleteView(TestCase, WagtailTestUtils):
# Check that the locale was not deleted
self.assertTrue(Locale.objects.filter(language_code='en').exists())
@override_settings(
LANGUAGE_CODE='de-at',
WAGTAIL_CONTENT_LANGUAGES=[
('en', 'English'),
('fr', 'French'),
('de', 'German'),
('pl', 'Polish'),
('ja', 'Japanese')
]
)
def test_can_delete_default_locale(self):
# The presence of the locale on the root page node (if that's the only thing using the
# locale) should not prevent deleting it
for lang in ('fr', 'de', 'pl', 'ja'):
Locale.objects.create(language_code=lang)
self.assertTrue(Page.get_first_root_node().locale.language_code, 'en')
Page.objects.filter(depth__gt=1).delete()
response = self.post()
# Should redirect back to index
self.assertRedirects(response, reverse('wagtaillocales:index'))
# Check that the locale was deleted
self.assertFalse(Locale.objects.filter(language_code='en').exists())
# root node's locale should now have been reassigned to the one matching the current
# LANGUAGE_CODE
self.assertTrue(Page.get_first_root_node().locale.language_code, 'de')
@override_settings(
LANGUAGE_CODE='de-at',
WAGTAIL_CONTENT_LANGUAGES=[
('en', 'English'),
('fr', 'French'),
('de', 'German'),
('pl', 'Polish'),
('ja', 'Japanese')
]
)
def test_can_delete_default_locale_when_language_code_has_no_locale(self):
Locale.objects.create(language_code='fr')
self.assertTrue(Page.get_first_root_node().locale.language_code, 'en')
Page.objects.filter(depth__gt=1).delete()
response = self.post()
# Should redirect back to index
self.assertRedirects(response, reverse('wagtaillocales:index'))
# Check that the locale was deleted
self.assertFalse(Locale.objects.filter(language_code='en').exists())
# root node's locale should now have been reassigned to 'fr' despite that not matching
# LANGUAGE_CODE (because it's the only remaining Locale record)
self.assertTrue(Page.get_first_root_node().locale.language_code, 'fr')
def test_cannot_delete_last_remaining_locale(self):
Page.objects.filter(depth__gt=1).delete()
response = self.post()
self.assertEqual(response.status_code, 200)
# Check error message
messages = list(get_messages(response.wsgi_request))
self.assertEqual(messages[0].level_tag, 'error')
self.assertEqual(messages[0].message, "This locale cannot be deleted because there are no other locales.\n\n\n\n\n")
# Check that the locale was not deleted
self.assertTrue(Locale.objects.filter(language_code='en').exists())

Wyświetl plik

@ -43,14 +43,25 @@ class EditView(generic.EditView):
class DeleteView(generic.DeleteView):
success_message = gettext_lazy("Locale '{0}' deleted.")
cannot_delete_message = gettext_lazy("This locale cannot be deleted because there are pages and/or other objects using it.")
page_title = gettext_lazy("Delete locale")
confirmation_message = gettext_lazy("Are you sure you want to delete this locale?")
template_name = 'wagtaillocales/confirm_delete.html'
queryset = Locale.all_objects.all()
def can_delete(self, locale):
return get_locale_usage(locale) == (0, 0)
if not self.queryset.exclude(pk=locale.pk).exists():
self.cannot_delete_message = gettext_lazy(
"This locale cannot be deleted because there are no other locales."
)
return False
if get_locale_usage(locale) != (0, 0):
self.cannot_delete_message = gettext_lazy(
"This locale cannot be deleted because there are pages and/or other objects using it."
)
return False
return True
def get_context_data(self, object=None):
context = context = super().get_context_data()