Skip to content

Commit 6e57308

Browse files
functionzzeemeli
andauthored
API Optimizations (#3827)
* API view field optimizations, N+1 fix in TermSearchListView, DynamicViewSerializer applied to ProjectLocale * Update test_views.py * change locale visibility for LocaleIndividualView * remove unused request check * Update pontoon/api/views.py Co-authored-by: Eemeli Aro <[email protected]> * tweak conditional logic * Update pontoon/api/views.py Co-authored-by: Eemeli Aro <[email protected]> * tweak set comprehension * add mixin for request fields, remove code dupes * remove unnecessary needs_* conditionals * Update pontoon/api/serializers.py Co-authored-by: Eemeli Aro <[email protected]> * Update pontoon/api/serializers.py Co-authored-by: Eemeli Aro <[email protected]> --------- Co-authored-by: Eemeli Aro <[email protected]>
1 parent df9e8c6 commit 6e57308

File tree

3 files changed

+200
-108
lines changed

3 files changed

+200
-108
lines changed

pontoon/api/serializers.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class Meta:
155155
]
156156

157157

158-
class ProjectLocaleSerializer(TranslationStatsMixin, serializers.ModelSerializer):
158+
class ProjectLocaleSerializer(TranslationStatsMixin, DynamicFieldsModelSerializer):
159159
locale = CompactLocaleSerializer(read_only=True)
160160
project = CompactProjectSerializer(read_only=True)
161161

@@ -190,10 +190,6 @@ def get_locales(self, obj):
190190
return [pl.locale.code for pl in getattr(obj, "fetched_project_locales", [])]
191191

192192
def get_localizations(self, obj):
193-
request = self.context.get("request")
194-
if not request:
195-
return None
196-
197193
project_locales = obj.project_locale.stats_data(project=obj)
198194
serialized = ProjectLocaleSerializer(project_locales, many=True).data
199195
return [
@@ -222,10 +218,6 @@ def get_projects(self, obj):
222218
return [pl.project.slug for pl in getattr(obj, "fetched_project_locales", [])]
223219

224220
def get_localizations(self, obj):
225-
request = self.context.get("request")
226-
if not request:
227-
return None
228-
229221
project_locales = obj.project_locale.stats_data(locale=obj)
230222
serialized = ProjectLocaleSerializer(project_locales, many=True).data
231223
return [{k: v for k, v in item.items() if k != "locale"} for item in serialized]
@@ -254,14 +246,10 @@ class Meta:
254246
]
255247

256248
def get_translation_text(self, obj):
257-
request = self.context.get("request")
258-
locale = request.query_params.get("locale") if request else None
259-
260-
if not locale:
261-
return None
249+
if hasattr(obj, "filtered_translations") and (ft := obj.filtered_translations):
250+
return ft[0].text
262251

263-
term = obj.translations.filter(locale__code=locale).first()
264-
return term.text if term else None
252+
return None
265253

266254

267255
class TranslationMemorySerializer(DynamicFieldsModelSerializer):
@@ -368,11 +356,6 @@ def __init__(self, *args, **kwargs):
368356
self.fields.pop("translations", None)
369357

370358
def get_translations(self, obj):
371-
request = self.context.get("request")
372-
373-
if not request:
374-
return None
375-
376359
return TranslationSerializer(
377360
obj.filtered_translations, many=True, context=self.context
378361
).data
@@ -385,11 +368,6 @@ class Meta(EntitySerializer.Meta):
385368
fields = EntitySerializer.Meta.fields + ["translation"]
386369

387370
def get_translation(self, obj):
388-
request = self.context.get("request")
389-
390-
if not request:
391-
return None
392-
393371
translation = (
394372
obj.filtered_translations[0] if obj.filtered_translations else None
395373
)

pontoon/api/tests/test_views.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,10 @@ def test_terminology_search(django_assert_num_queries):
940940
code="kg",
941941
name="Klingon",
942942
)
943+
locale_b = LocaleFactory(
944+
code="gs",
945+
name="Geonosian",
946+
)
943947
term1 = Term.objects.create(
944948
text="open",
945949
part_of_speech="verb",
@@ -952,17 +956,31 @@ def test_terminology_search(django_assert_num_queries):
952956
definition="Shut or block access",
953957
usage="Close the door.",
954958
)
959+
term3 = Term.objects.create(
960+
text="opened",
961+
part_of_speech="verb",
962+
definition="Allow access (past tense)",
963+
usage="Opened the door.",
964+
)
965+
term4 = Term.objects.create(
966+
text="click",
967+
part_of_speech="verb",
968+
definition="press",
969+
usage="Click the button.",
970+
)
955971

956972
TermTranslation.objects.create(term=term1, locale=locale_a, text="odpreti")
957973
TermTranslation.objects.create(term=term2, locale=locale_a, text="zapreti")
974+
TermTranslation.objects.create(term=term3, locale=locale_a, text="odprto")
975+
TermTranslation.objects.create(term=term4, locale=locale_b, text="klikni")
958976

959-
with django_assert_num_queries(5):
977+
with django_assert_num_queries(3):
960978
response = APIClient().get("/api/v2/search/terminology/?text=open&locale=kg")
961979

962980
assert response.status_code == 200
963981

964982
assert response.data == {
965-
"count": 1,
983+
"count": 2,
966984
"next": None,
967985
"previous": None,
968986
"results": [
@@ -973,7 +991,15 @@ def test_terminology_search(django_assert_num_queries):
973991
"translation_text": "odpreti",
974992
"usage": "Open the door.",
975993
"notes": "",
976-
}
994+
},
995+
{
996+
"definition": "Allow access (past tense)",
997+
"part_of_speech": "verb",
998+
"text": "opened",
999+
"translation_text": "odprto",
1000+
"usage": "Opened the door.",
1001+
"notes": "",
1002+
},
9771003
],
9781004
}
9791005

0 commit comments

Comments
 (0)