From 4bcd6086e077c8b5ed1d4ba6dd43d9d25606bcef Mon Sep 17 00:00:00 2001 From: Dario Marcelino Date: Fri, 22 Dec 2017 18:46:57 +0000 Subject: [PATCH] Patch slugurl to accept original language slug no matter what is the user's current language --- wagtail_modeltranslation/apps.py | 3 + wagtail_modeltranslation/contextlib.py | 21 +++++ .../commands/update_translation_fields.py | 76 +------------------ .../patch_wagtailadmin.py | 1 - wagtail_modeltranslation/patch_wagtailcore.py | 26 +++++++ 5 files changed, 53 insertions(+), 74 deletions(-) create mode 100644 wagtail_modeltranslation/contextlib.py create mode 100644 wagtail_modeltranslation/patch_wagtailcore.py diff --git a/wagtail_modeltranslation/apps.py b/wagtail_modeltranslation/apps.py index f77efc0..8154142 100644 --- a/wagtail_modeltranslation/apps.py +++ b/wagtail_modeltranslation/apps.py @@ -19,3 +19,6 @@ class ModeltranslationConfig(AppConfig): from .patch_wagtailadmin import patch_wagtail_models patch_wagtail_models() + + from .patch_wagtailcore import patch_wagtail_tags + patch_wagtail_tags() diff --git a/wagtail_modeltranslation/contextlib.py b/wagtail_modeltranslation/contextlib.py new file mode 100644 index 0000000..2f6d207 --- /dev/null +++ b/wagtail_modeltranslation/contextlib.py @@ -0,0 +1,21 @@ +from django.utils.translation import activate +from modeltranslation.utils import get_language + + +class set_language: + """ + Context manager to safely change language momentarily + + Usage: + with set_language('en'): + en_url = obj.get_absolute_url() + """ + def __init__(self, lang): + self.language = lang + self.current_language = get_language() + + def __enter__(self): + activate(self.language) + + def __exit__(self, exctype, excinst, exctb): + activate(self.current_language) diff --git a/wagtail_modeltranslation/management/commands/update_translation_fields.py b/wagtail_modeltranslation/management/commands/update_translation_fields.py index abe091f..68ac2c5 100755 --- a/wagtail_modeltranslation/management/commands/update_translation_fields.py +++ b/wagtail_modeltranslation/management/commands/update_translation_fields.py @@ -1,77 +1,7 @@ # coding: utf-8 -from django.core.management.base import BaseCommand -from django.db import connection -from django.db.models import F, Q -from modeltranslation.settings import DEFAULT_LANGUAGE -from modeltranslation.translator import translator -from modeltranslation.utils import build_localized_fieldname -from wagtail.wagtailcore.models import Page +from modeltranslation.management.commands.update_translation_fields import Command as UpdateTranslationFieldsCommand -class Command(BaseCommand): - help = ('Updates empty values of default translation fields using' - ' values from original fields (in all translated models).') - - def handle(self, **options): - verbosity = int(options['verbosity']) - if verbosity > 0: - self.stdout.write( - "Using default language: %s\n" % DEFAULT_LANGUAGE) - models = translator.get_registered_models(abstract=False) - for model in models: - if verbosity > 0: - self.stdout.write("Updating data of model '%s'\n" % model) - opts = translator.get_options_for_model(model) - for field_name in opts.fields.keys(): - def_lang_fieldname = build_localized_fieldname( - field_name, DEFAULT_LANGUAGE) - - # We'll only update fields which do not have an existing value - q = Q(**{def_lang_fieldname: None}) - field = model._meta.get_field(field_name) - if field.empty_strings_allowed: - q |= Q(**{def_lang_fieldname: ''}) - - if issubclass(model, Page): - for obj in model._default_manager.filter(q): - # Get table description in order to know if field is - # in child or parent table - # TODO: Tested only on PostgreSQL engine - db_table = model._meta.db_table - db_table_desc = connection.introspection. \ - get_table_description( - connection.cursor(), db_table) - # original field in child class - if field_name in [x.name for x in db_table_desc]: - raw = model._default_manager.raw( - 'SELECT *, %s AS original_field FROM %s \ - WHERE page_ptr_id=%d LIMIT 1' % ( - field_name, db_table, obj.page_ptr_id))[0] - setattr( - obj, def_lang_fieldname, raw.original_field) - # field is a foreign key - elif (field_name + '_id') in \ - [x.name for x in db_table_desc]: - raw = model._default_manager.raw( - 'SELECT *, %s AS original_field FROM %s \ - WHERE page_ptr_id=%d LIMIT 1' % ( - field_name + '_id', - db_table, - obj.page_ptr_id))[0] - setattr( - obj, - def_lang_fieldname + '_id', - raw.original_field) - # original field parent class - else: - raw = Page._default_manager.raw( - 'SELECT *, %s AS original_field FROM \ - wagtailcore_page WHERE id=%d LIMIT 1' % ( - field_name, obj.page_ptr_id))[0] - setattr( - obj, def_lang_fieldname, raw.original_field) - obj.save(update_fields=[def_lang_fieldname]) - else: - model._default_manager.filter(q).rewrite(False).update( - **{def_lang_fieldname: F(field_name)}) +class Command(UpdateTranslationFieldsCommand): + pass diff --git a/wagtail_modeltranslation/patch_wagtailadmin.py b/wagtail_modeltranslation/patch_wagtailadmin.py index cb0fecc..0a2f460 100644 --- a/wagtail_modeltranslation/patch_wagtailadmin.py +++ b/wagtail_modeltranslation/patch_wagtailadmin.py @@ -552,4 +552,3 @@ def patch_wagtail_models(): for model_class in registered_models: if issubclass(model_class, Page) or model_class in get_snippet_models() or issubclass(model_class, BaseSetting): WagtailTranslator(model_class) - diff --git a/wagtail_modeltranslation/patch_wagtailcore.py b/wagtail_modeltranslation/patch_wagtailcore.py new file mode 100644 index 0000000..249a89d --- /dev/null +++ b/wagtail_modeltranslation/patch_wagtailcore.py @@ -0,0 +1,26 @@ +from wagtail.wagtailcore.models import Page +from wagtail.wagtailcore.templatetags import wagtailcore_tags + +from modeltranslation.settings import DEFAULT_LANGUAGE + +from .contextlib import set_language + + +# decorate MigrationAutodetector.changes so we can silently remove wagtailcore changes +def slugurl_decorator(func): + def wrapper(context, slug): + with set_language(DEFAULT_LANGUAGE): + page = Page.objects.filter(slug=slug).first() + + if page: + return page.relative_url(context['request'].site) + else: + # default to original function + return func(context, slug) + + return wrapper + + +def patch_wagtail_tags(): + # decorate slugurl tag so `{% slugurl 'default_lang_slug' %}` always works with original slug + wagtailcore_tags.slugurl = slugurl_decorator(wagtailcore_tags.slugurl)