Merge pull request #142 from dmarcelino/original_slug

#141: Ensure original slug field is always saved in the same language
This commit is contained in:
Diogo Marques 2017-12-14 11:53:46 +00:00 committed by GitHub
commit 37eec32f7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 156 additions and 6 deletions

View file

@ -23,8 +23,36 @@ If, for example, you're using wagtail-embedvideos the EmbedVideoChooserPanel is
Default: ``[]`` (empty list)
This settings behaves as the above but should be used for panels that are composed by other panels (MultiFieldPanel or FieldRowPanel for example).
This setting behaves as the above but should be used for panels that are composed by other panels (MultiFieldPanel or FieldRowPanel for example).
.. code-block:: python
WAGTAILMODELTRANSLATION_CUSTOM_COMPOSED_PANELS = ['app_x.module_y.PanelZ']
``WAGTAILMODELTRANSLATION_ORIGINAL_SLUG_LANGUAGE``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. versionadded:: 0.6.0
Default: ``None``
This setting enables consistency for the original (not translated) 'slug' value that is saved to the ``Page`` model table (wagtailcore_page). The value saved to the DB will be independent of user's current language and instead will rely on this setting's language.
This is specially useful when Wagtail pages are edited by users of different languages and the site makes use of `slugurl <http://docs.wagtail.io/en/latest/topics/writing_templates.html#slugurl>`_.
``None``
[set by default]
Setting turned off. Behaviour is the same as django-modeltranslation, meaning the value of the original slug field is undetermined (check `The State of the Original Field <http://django-modeltranslation.readthedocs.io/en/latest/usage.html#the-state-of-the-original-field>`_).
``'default'``
Original slug field saved to the DB is in django-modeltranslation's default language.
``'xx'`` (language code)
Use a language code to ensure the value saved to the original slug field is in the chosen language. For example: ``'en'``.
Example:
.. code-block:: python
WAGTAILMODELTRANSLATION_ORIGINAL_SLUG_LANGUAGE = 'default'

View file

@ -61,6 +61,7 @@ def runtests():
('en', 'English'),
),
MIDDLEWARE_CLASSES=(),
WAGTAILMODELTRANSLATION_ORIGINAL_SLUG_LANGUAGE='default',
)
if django.VERSION >= (1, 7):

View file

@ -2,7 +2,7 @@
import copy
import logging
from django.core.exceptions import ValidationError
from django.core.exceptions import ValidationError, FieldDoesNotExist
from django.core.urlresolvers import reverse
from django.db import transaction
from django.http import Http404
@ -23,7 +23,7 @@ from wagtail.wagtailsearch.index import SearchField
from wagtail.wagtailsnippets.models import get_snippet_models
from wagtail.wagtailsnippets.views.snippets import SNIPPET_EDIT_HANDLERS
from wagtail_modeltranslation.settings import CUSTOM_SIMPLE_PANELS, CUSTOM_COMPOSED_PANELS
from wagtail_modeltranslation.settings import CUSTOM_SIMPLE_PANELS, CUSTOM_COMPOSED_PANELS, ORIGINAL_SLUG_LANGUAGE
from wagtail_modeltranslation.utils import compare_class_tree_depth
logger = logging.getLogger('wagtail.core')
@ -88,8 +88,15 @@ class WagtailTranslator(object):
translated_field.field_name = build_localized_fieldname(field.field_name, language)
model.search_fields = list(model.search_fields) + [translated_field]
# OVERRIDE PAGE METHODS
# SLUG FIELD PATCHING
try:
slug_field = model._meta.get_field('slug')
_patch_pre_save(slug_field)
except FieldDoesNotExist:
pass
# OVERRIDE PAGE METHODS
model.move = _new_move
model.set_url_path = _new_set_url_path
model.route = _new_route
@ -201,7 +208,6 @@ class WagtailTranslator(object):
# patched, leaving the original untouched
return panel
# Overridden Page methods adapted to the translated fields
@transaction.atomic # only commit when all descendants are properly updated
@ -403,6 +409,30 @@ def _patch_clean(model):
model.clean = clean
def _patch_pre_save(field):
if not ORIGINAL_SLUG_LANGUAGE:
return
if ORIGINAL_SLUG_LANGUAGE == 'default':
reference_slug_language = mt_settings.DEFAULT_LANGUAGE
else:
reference_slug_language = ORIGINAL_SLUG_LANGUAGE
def pre_save(self, model_instance, add):
"""
Returns slug field's value using the language set by `WAGTAILMODELTRANSLATION_ORIGINAL_SLUG_LANGUAGE`
just before saving.
"""
current_language = get_language()
# using ORIGINAL_SLUG_LANGUAGE makes Page's slug value consistent
trans_real.activate(reference_slug_language)
value = getattr(model_instance, self.attname)
trans_real.activate(current_language)
return value
field.pre_save = pre_save.__get__(field)
def patch_wagtail_models():
# After all models being registered the Page or BaseSetting subclasses and snippets are patched
registered_models = translator.get_registered_models()

View file

@ -10,3 +10,5 @@ CUSTOM_SIMPLE_PANELS = [import_from_string(panel_class) for panel_class in
getattr(settings, 'WAGTAILMODELTRANSLATION_CUSTOM_SIMPLE_PANELS', [])]
CUSTOM_COMPOSED_PANELS = [import_from_string(panel_class) for panel_class in
getattr(settings, 'WAGTAILMODELTRANSLATION_CUSTOM_COMPOSED_PANELS', [])]
ORIGINAL_SLUG_LANGUAGE = getattr(settings, 'WAGTAILMODELTRANSLATION_ORIGINAL_SLUG_LANGUAGE', None)

View file

@ -5,7 +5,7 @@ import django
from django.apps import apps as django_apps
from django.core.exceptions import ValidationError
from django.core.management import call_command
from django.test import TestCase, TransactionTestCase
from django.test import TestCase, TransactionTestCase, RequestFactory
from django.test.utils import override_settings
from django.utils.translation import get_language, trans_real
from modeltranslation import settings as mt_settings, translator
@ -336,6 +336,95 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
self.assertRaises(ValidationError, child2.clean)
def test_original_slug_update(self):
from wagtail.wagtailcore.models import Page
# save the page in the default language
root = models.TestRootPage(title='original slug', title_de='originalschnecke', depth=1, path='0002',
slug_en='test-slug-en', slug_de='test-slug-de')
root.save()
# some control checks, we don't expect any surprises here
self.assertEqual(root.slug, 'test-slug-de', 'slug has the wrong value.')
self.assertEqual(root.slug_de, 'test-slug-de', 'slug_de has the wrong value.')
self.assertEqual(root.slug_en, 'test-slug-en', 'slug_en has the wrong value.')
# fetches the correct Page using slug
page = Page.objects.filter(slug='test-slug-de').first()
self.assertEqual(page.specific, root, 'The wrong page was retrieved from DB.')
trans_real.activate('en')
# fetches the correct Page using slug using non-default language
page = Page.objects.filter(slug='test-slug-de').first()
self.assertEqual(page.specific, root, 'The wrong page was retrieved from DB.')
# save the page 2 in the non-default language
root2 = models.TestRootPage(title='original slug 2', title_de='originalschnecke 2', depth=1, path='0003',
slug_en='test-slug2-en', slug_de='test-slug2-de')
root2.save()
# sanity checks
self.assertEqual(root2.slug, 'test-slug2-en', 'slug has the wrong value.')
self.assertEqual(root2.slug_de, 'test-slug2-de', 'slug_de has the wrong value.')
self.assertEqual(root2.slug_en, 'test-slug2-en', 'slug_en has the wrong value.')
# fetches the correct Page using slug using non-default language
page = Page.objects.filter(slug='test-slug2-de').first()
self.assertEqual(page.specific, root2, 'The wrong page was retrieved from DB.')
trans_real.activate('de')
# fetches the correct Page using slug using default language
page = Page.objects.filter(slug='test-slug2-de').first()
self.assertEqual(page.specific, root2, 'The wrong page was retrieved from DB.')
def test_relative_url(self):
from wagtail.wagtailcore.models import Site
# Create a test Site with a root page
root = models.TestRootPage(title='title slugurl', depth=1, path='0004',
slug_en='title_slugurl_en', slug_de='title_slugurl_de')
root.save()
site = Site(root_page=root)
site.save()
# Add children to the root
child = root.add_child(
instance=models.TestSlugPage1(title='child1 slugurl',
slug_en='child-slugurl-en', slug_de='child-slugurl-de',
depth=2, path='00040001')
)
child.save_revision().publish()
url_1_de = child.relative_url(site)
self.assertEqual(url_1_de, '/de/child-slugurl-de/',
'When using the default language, slugurl produces the wrong url.')
trans_real.activate('en')
url_1_en = child.relative_url(site)
self.assertEqual(url_1_en, '/en/child-slugurl-en/',
'When using non-default language, slugurl produces the wrong url.')
# Add children using non-default language
child2 = root.add_child(
instance=models.TestSlugPage2(title='child2 slugurl', title_de='child2 slugurl DE',
slug_de='child2-slugurl-de', slug_en='child2-slugurl-en',
depth=2, path='00040002')
)
child2.save_revision().publish()
url_2_en = child2.relative_url(site)
self.assertEqual(url_2_en, '/en/child2-slugurl-en/',
'When using non-default language, slugurl produces the wrong url.')
trans_real.activate('de')
url_2_de = child2.relative_url(site)
self.assertEqual(url_2_de, '/de/child2-slugurl-de/',
'When using non-default language, slugurl produces the wrong url.')
def test_searchfield_patching(self):
# Check if the search fields have the original field plus the translated ones
expected_fields = ['title', 'title_de', 'title_en', 'description', 'description_de', 'description_en']