Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Generated by Django 5.2.8 on 2025-12-12 09:55

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('academy', '0003_mariadb_uuid_conversion'),
]

operations = [
migrations.AddField(
model_name='academy',
name='long_description_en',
field=models.TextField(help_text='Long description of the academy.', null=True),
),
migrations.AddField(
model_name='academy',
name='long_description_es',
field=models.TextField(help_text='Long description of the academy.', null=True),
),
migrations.AddField(
model_name='academy',
name='short_description_en',
field=models.TextField(help_text='Short description of the academy.', null=True),
),
migrations.AddField(
model_name='academy',
name='short_description_es',
field=models.TextField(help_text='Short description of the academy.', null=True),
),
migrations.AddField(
model_name='academy',
name='title_en',
field=models.CharField(help_text='Academy title', max_length=255, null=True),
),
migrations.AddField(
model_name='academy',
name='title_es',
field=models.CharField(help_text='Academy title', max_length=255, null=True),
),
migrations.AddField(
model_name='historicalacademy',
name='long_description_en',
field=models.TextField(help_text='Long description of the academy.', null=True),
),
migrations.AddField(
model_name='historicalacademy',
name='long_description_es',
field=models.TextField(help_text='Long description of the academy.', null=True),
),
migrations.AddField(
model_name='historicalacademy',
name='short_description_en',
field=models.TextField(help_text='Short description of the academy.', null=True),
),
migrations.AddField(
model_name='historicalacademy',
name='short_description_es',
field=models.TextField(help_text='Short description of the academy.', null=True),
),
migrations.AddField(
model_name='historicalacademy',
name='title_en',
field=models.CharField(help_text='Academy title', max_length=255, null=True),
),
migrations.AddField(
model_name='historicalacademy',
name='title_es',
field=models.CharField(help_text='Academy title', max_length=255, null=True),
),
migrations.AddField(
model_name='tag',
name='description_en',
field=models.TextField(help_text='Tag description.', null=True),
),
migrations.AddField(
model_name='tag',
name='description_es',
field=models.TextField(help_text='Tag description.', null=True),
),
migrations.AddField(
model_name='tag',
name='title_en',
field=models.CharField(help_text='Tag title', max_length=255, null=True),
),
migrations.AddField(
model_name='tag',
name='title_es',
field=models.CharField(help_text='Tag title', max_length=255, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from django.db import migrations
from django.db.models import Q


def batch_update_fields(queryset, field_mapping, batch_size=500):
"""
Helper function to update fields in batches using iterator and bulk_update.

Args:
queryset: Django queryset (can be filtered)
field_mapping: dict mapping source field -> target field (e.g., {'title': 'title_en'})
batch_size: number of records to process at once
"""
records_to_update = []

for record in queryset.iterator(chunk_size=batch_size):
updated = False

for source_field, target_field in field_mapping.items():
source_value = getattr(record, source_field)
target_value = getattr(record, target_field)

# Only copy if target is empty but source has data
if not target_value and source_value:
setattr(record, target_field, source_value)
updated = True

if updated:
records_to_update.append(record)

# Bulk update when batch is full
if len(records_to_update) >= batch_size:
queryset.model.objects.bulk_update(
records_to_update,
list(field_mapping.values()),
batch_size=batch_size
)
records_to_update = []

# Update any remaining records
if records_to_update:
queryset.model.objects.bulk_update(
records_to_update,
list(field_mapping.values()),
batch_size=batch_size
)


def populate_translation_fields(apps, schema_editor):
"""
Populate English translation fields from original fields for Academy and Tag models.
"""
Academy = apps.get_model('academy', 'Academy')
Tag = apps.get_model('academy', 'Tag')

batch_size = 500

# Update Academy records, only fetch those needing translation
academy_filter = (
Q(title_en__isnull=True) | Q(title_en='') |
Q(short_description_en__isnull=True) | Q(short_description_en='') |
Q(long_description_en__isnull=True) | Q(long_description_en='')
)
batch_update_fields(
Academy.objects.filter(academy_filter),
{
'title': 'title_en',
'short_description': 'short_description_en',
'long_description': 'long_description_en',
},
batch_size
)

# Update Tag records, only fetch those needing translation
tag_filter = (
Q(title_en__isnull=True) | Q(title_en='') |
Q(description_en__isnull=True) | Q(description_en='')
)
batch_update_fields(
Tag.objects.filter(tag_filter),
{
'title': 'title_en',
'description': 'description_en',
},
batch_size
)


class Migration(migrations.Migration):

dependencies = [
('academy', '0004_academy_long_description_en_and_more'),
]

operations = [
migrations.RunPython(populate_translation_fields, migrations.RunPython.noop),
]
3 changes: 0 additions & 3 deletions enterprise_catalog/apps/academy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from django.db import models
from django.utils.translation import gettext as _
from model_utils.models import TimeStampedModel
from simple_history.models import HistoricalRecords

from enterprise_catalog.apps.catalog.models import (
ContentMetadata,
Expand Down Expand Up @@ -52,8 +51,6 @@ class Academy(TimeStampedModel):

tags = models.ManyToManyField(Tag, related_name='academies')

history = HistoricalRecords()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


class Meta:
verbose_name = _('Academy')
verbose_name_plural = _('Academies')
Expand Down
37 changes: 37 additions & 0 deletions enterprise_catalog/apps/academy/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
Tests for Academy app models.
"""
from django.test import TestCase

from enterprise_catalog.apps.academy.tests.factories import (
AcademyFactory,
TagFactory,
)


class TagModelTests(TestCase):
"""
Tests for the Tag model.
"""

def test_tag_str_method(self):
"""
Test that the Tag __str__ method returns the expected format.
"""
tag = TagFactory(title='Test Tag')
expected_str = '<Tag title="Test Tag">'
self.assertEqual(str(tag), expected_str)


class AcademyModelTests(TestCase):
"""
Tests for the Academy model.
"""

def test_academy_creation(self):
"""
Test that an Academy can be created successfully.
"""
academy = AcademyFactory(title='Test Academy')
self.assertIsNotNone(academy.uuid)
self.assertEqual(academy.title, 'Test Academy')
18 changes: 18 additions & 0 deletions enterprise_catalog/apps/academy/translation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import simple_history
from modeltranslation.translator import TranslationOptions, register

from enterprise_catalog.apps.academy.models import Academy, Tag


@register(Academy)
class AcademyTranslationOptions(TranslationOptions):
fields = ('title', 'short_description', 'long_description',)


@register(Tag)
class TagTranslationOptions(TranslationOptions):
fields = ('title', 'description',)


# https://django-simple-history.readthedocs.io/en/latest/common_issues.html#usage-with-django-modeltranslation
simple_history.register(Academy, inherit=True)
Comment thread
muhammad-ammar marked this conversation as resolved.
14 changes: 13 additions & 1 deletion enterprise_catalog/apps/api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,14 @@ class AcademyTagsListSerializer(serializers.ListSerializer): # pylint: disable=
def to_representation(self, obj): # pylint: disable=arguments-renamed
"""Filter academy tags with no index hits. """
tags = super().to_representation(obj)

# Map tag IDs to title_en for lookup
title_en_by_id = {tag.id: tag.title_en for tag in obj}

# Add title_en to each serialized tag
for tag_dict in tags:
tag_dict['title_en'] = title_en_by_id.get(tag_dict['id'])

algolia_client = get_initialized_algolia_client()
academy_uuid = self.context.get('academy_uuid')
enterprise_uuid = self.context.get('enterprise_uuid')
Expand All @@ -482,8 +490,12 @@ def to_representation(self, obj): # pylint: disable=arguments-renamed
tag_titles_with_results.append(hit.get('value'))
tags_with_results = []
for tag in tags:
# Match using both current active language title and English title
tag_title = tag['title']
if tag_title in tag_titles_with_results:
tag_title_en = tag.get('title_en', tag_title)
if tag_title in tag_titles_with_results or tag_title_en in tag_titles_with_results:
# Remove title_en before adding to results (only used for internal matching)
tag.pop('title_en', None)
tags_with_results.append(tag)
return tags_with_results

Expand Down
Loading