Skip to content

Commit 879bae6

Browse files
authored
misc(variants): change index to TextField and remove OperationalError (#18262)
* Change index to TextField and remove OperationalError. * Use MD5 index for variants.
1 parent ae22eaf commit 879bae6

File tree

5 files changed

+57
-16
lines changed

5 files changed

+57
-16
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright © Michal Čihař <michal@weblate.org>
2+
#
3+
# SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
# Generated by Django 5.2.11 on 2026-02-28 00:00
6+
7+
from django.db import migrations, models
8+
from django.db.models.functions import MD5
9+
10+
11+
class Migration(migrations.Migration):
12+
dependencies = [
13+
("trans", "0065_alter_change_action"),
14+
]
15+
16+
operations = [
17+
migrations.AlterField(
18+
model_name="variant",
19+
name="key",
20+
field=models.TextField(),
21+
),
22+
migrations.AlterUniqueTogether(
23+
name="variant",
24+
unique_together=set(),
25+
),
26+
migrations.AddConstraint(
27+
model_name="variant",
28+
constraint=models.UniqueConstraint(
29+
MD5("key"),
30+
models.F("component"),
31+
models.F("variant_regex"),
32+
name="trans_variant_unique_key_md5",
33+
),
34+
),
35+
]

weblate/trans/models/component.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
)
2727
from django.core.validators import MaxValueValidator
2828
from django.db import IntegrityError, models, transaction
29-
from django.db.models import Count, F, Q
29+
from django.db.models import Count, F, Q, Value
30+
from django.db.models.functions import MD5
3031
from django.db.models.signals import m2m_changed
3132
from django.dispatch import receiver
3233
from django.utils.functional import cached_property
@@ -3715,10 +3716,10 @@ def update_variants(self, updated_units=None) -> None:
37153716
for unit in units.iterator():
37163717
if variant_re.findall(unit.context):
37173718
key = variant_re.sub("", unit.context)
3718-
if key in variant_updates:
3719-
variant = variant_updates[key][0]
3720-
else:
3721-
variant = Variant.objects.get_or_create(
3719+
if key not in variant_updates:
3720+
variant = Variant.objects.filter(
3721+
key__md5=MD5(Value(key))
3722+
).get_or_create(
37223723
key=key, component=self, variant_regex=self.variant_regex
37233724
)[0]
37243725
variant_updates[key] = (variant, [])

weblate/trans/models/unit.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -808,9 +808,9 @@ def update_variants(self) -> None:
808808

809809
# Add new variant
810810
if new_variant:
811-
variant = Variant.objects.get_or_create(
812-
key=new_variant, component=component, variant_regex=""
813-
)[0]
811+
variant = Variant.objects.filter(
812+
key__md5=MD5(Value(new_variant))
813+
).get_or_create(key=new_variant, component=component, variant_regex="")[0]
814814
variant.defining_units.add(self)
815815

816816
# Update variant links

weblate/trans/models/variant.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
# SPDX-License-Identifier: GPL-3.0-or-later
44

55
from django.db import models
6+
from django.db.models.functions import MD5
67

7-
from weblate.trans.defines import VARIANT_KEY_LENGTH, VARIANT_REGEX_LENGTH
8+
from weblate.trans.defines import VARIANT_REGEX_LENGTH
89
from weblate.trans.fields import RegexField
910

1011

@@ -13,15 +14,20 @@ class Variant(models.Model):
1314
"trans.Component", on_delete=models.deletion.CASCADE, db_index=False
1415
)
1516
variant_regex = RegexField(max_length=VARIANT_REGEX_LENGTH, blank=True)
16-
# This really should be a TextField, but it does not work with unique
17-
# index and MySQL
18-
key = models.CharField(max_length=VARIANT_KEY_LENGTH)
17+
key = models.TextField()
1918
defining_units = models.ManyToManyField(
2019
"trans.Unit", related_name="defined_variants"
2120
)
2221

2322
class Meta:
24-
unique_together = (("component", "key", "variant_regex"),)
23+
constraints = [ # noqa: RUF012
24+
models.UniqueConstraint(
25+
MD5("key"),
26+
"component",
27+
"variant_regex",
28+
name="trans_variant_unique_key_md5",
29+
),
30+
]
2531
verbose_name = "variant definition"
2632
verbose_name_plural = "variant definitions"
2733

weblate/utils/search.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from dateutil.parser import parse as dateutil_parse
1717
from django.db import transaction
1818
from django.db.models import Count, Exists, F, OuterRef, Q, Value
19-
from django.db.utils import DataError, OperationalError
19+
from django.db.utils import DataError
2020
from django.http import Http404
2121
from django.utils import timezone
2222
from django.utils.translation import gettext
@@ -476,8 +476,7 @@ def as_query(self, context: dict) -> Q:
476476
Unit.objects.annotate(test=Value("")).filter(
477477
test__trgm_regex=match.expr
478478
).exists()
479-
except (DataError, OperationalError) as error:
480-
# PostgreSQL raises DataError, MySQL OperationalError
479+
except DataError as error:
481480
raise SearchQueryError(
482481
gettext("Invalid regular expression: {}").format(error)
483482
) from error

0 commit comments

Comments
 (0)