Skip to content

Commit

Permalink
Fix copy_for_translation on inherited and clusterable models
Browse files Browse the repository at this point in the history
  • Loading branch information
kaedroho authored and gasman committed Mar 5, 2021
1 parent 2d66f49 commit cb0c643
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 4 deletions.
15 changes: 12 additions & 3 deletions wagtail/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,11 @@ def _copy(source, exclude_fields=None, update_attrs=None):
continue
setattr(target, field, value)

child_object_map = source.copy_all_child_relations(target, exclude=exclude_fields)
if isinstance(source, ClusterableModel):
child_object_map = source.copy_all_child_relations(target, exclude=exclude_fields)
else:
child_object_map = {}

return target, child_object_map


Expand Down Expand Up @@ -489,10 +493,15 @@ def copy_for_translation(self, locale):
Note that the copy is initially unsaved.
"""
translated = self.__class__.objects.get(id=self.id)
translated.id = None
translated, child_object_map = _copy(self)
translated.locale = locale

# Update locale on any translatable child objects as well
# Note: If this is not a subclass of ClusterableModel, child_object_map will always be '{}'
for (child_relation, old_pk), child_object in child_object_map.items():
if isinstance(child_object, TranslatableMixin):
child_object.locale = locale

return translated

def get_default_locale(self):
Expand Down
44 changes: 43 additions & 1 deletion wagtail/core/tests/test_translatablemixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
from django.test import TestCase

from wagtail.core.models import Locale
from wagtail.tests.i18n.models import InheritedTestModel, TestModel
from wagtail.tests.i18n.models import (
ClusterableTestModel, ClusterableTestModelChild, ClusterableTestModelTranslatableChild,
InheritedTestModel, TestModel)


def make_test_instance(model=None, **kwargs):
Expand Down Expand Up @@ -108,6 +110,46 @@ def test_get_translation_model(self):
inherited_model = make_test_instance(model=InheritedTestModel)
self.assertEqual(inherited_model.get_translation_model(), TestModel)

def test_copy_inherited_model_for_translation(self):
instance = make_test_instance(model=InheritedTestModel)
copy = instance.copy_for_translation(locale=self.another_locale)

self.assertNotEqual(copy, instance)
self.assertEqual(copy.translation_key, instance.translation_key)
self.assertEqual(copy.locale, self.another_locale)

def test_copy_clusterable_model_for_translation(self):
instance = ClusterableTestModel.objects.create(
title="A test clusterable model",
children=[
ClusterableTestModelChild(field="A non-translatable child object"),
],
translatable_children=[
ClusterableTestModelTranslatableChild(field="A translatable child object"),
]
)

copy = instance.copy_for_translation(locale=self.another_locale)

instance_child = instance.children.get()
copy_child = copy.children.get()
instance_translatable_child = instance.translatable_children.get()
copy_translatable_child = copy.translatable_children.get()

self.assertNotEqual(copy, instance)
self.assertEqual(copy.translation_key, instance.translation_key)
self.assertEqual(copy.locale, self.another_locale)

# Check children were copied
self.assertNotEqual(copy_child, instance_child)
self.assertEqual(copy_child.field, "A non-translatable child object")
self.assertNotEqual(copy_translatable_child, instance_translatable_child)
self.assertEqual(copy_translatable_child.field, "A translatable child object")

# Check the translatable childs locale was updated but translation key is the same
self.assertEqual(copy_translatable_child.translation_key, instance_translatable_child.translation_key)
self.assertEqual(copy_translatable_child.locale, self.another_locale)


class TestLocalized(TestCase):
def setUp(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Generated by Django 3.1.6 on 2021-02-16 18:04

from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
import uuid


class Migration(migrations.Migration):

dependencies = [
('wagtailcore', '0061_change_promote_tab_helpt_text_and_verbose_names'),
('i18n', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='ClusterableTestModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('translation_key', models.UUIDField(default=uuid.uuid4, editable=False)),
('title', models.CharField(max_length=255)),
('locale', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale')),
],
options={
'abstract': False,
'unique_together': {('translation_key', 'locale')},
},
),
migrations.CreateModel(
name='ClusterableTestModelChild',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
('field', models.TextField()),
('parent', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='children', to='i18n.clusterabletestmodel')),
],
options={
'ordering': ['sort_order'],
'abstract': False,
},
),
migrations.CreateModel(
name='ClusterableTestModelTranslatableChild',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('translation_key', models.UUIDField(default=uuid.uuid4, editable=False)),
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
('field', models.TextField()),
('locale', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale')),
('parent', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='translatable_children', to='i18n.clusterabletestmodel')),
],
options={
'ordering': ['sort_order'],
'abstract': False,
'unique_together': {('translation_key', 'locale')},
},
),
]
18 changes: 18 additions & 0 deletions wagtail/tests/i18n/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.db import models
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel

from wagtail.core.models import Orderable, Page, TranslatableMixin

Expand Down Expand Up @@ -30,3 +31,20 @@ class TestNonParentalChildObject(TranslatableMixin, Orderable):
TestPage, on_delete=models.CASCADE, related_name="test_nonparentalchildobjects"
)
field = models.TextField()


class ClusterableTestModel(TranslatableMixin, ClusterableModel):
title = models.CharField(max_length=255)


class ClusterableTestModelChild(Orderable):
parent = ParentalKey(ClusterableTestModel, on_delete=models.CASCADE, related_name='children')
field = models.TextField()


class ClusterableTestModelTranslatableChild(TranslatableMixin, Orderable):
parent = ParentalKey(ClusterableTestModel, on_delete=models.CASCADE, related_name='translatable_children')
field = models.TextField()

class Meta(TranslatableMixin.Meta, Orderable.Meta):
pass

0 comments on commit cb0c643

Please sign in to comment.