From 464ea1a164e463441b1dd4e7b33d0dc2109e1189 Mon Sep 17 00:00:00 2001 From: Chatewgne Date: Tue, 26 Dec 2023 13:21:27 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=AB=20[IMPR]=20Fix=20sublanguage=20usa?= =?UTF-8?q?ge=20(refs=20#3801)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/management/commands/sync_mobile.py | 27 +++++------ .../api/tests/test_mobile/test_sync_mobile.py | 46 +++++++++++-------- geotrek/api/v2/filters.py | 9 ++-- geotrek/api/v2/utils.py | 5 +- geotrek/api/v2/views/trekking.py | 9 ++-- geotrek/common/forms.py | 9 ++-- .../common/management/commands/sync_rando.py | 2 +- .../update_post_migration_languages.py | 24 +++++----- .../migrations/0008_auto_20200228_1830.py | 4 +- geotrek/common/mixins/models.py | 7 +-- geotrek/common/mixins/views.py | 3 +- geotrek/common/parsers.py | 7 +-- geotrek/common/tests/test_sync.py | 2 +- geotrek/common/urls.py | 2 +- geotrek/common/views.py | 13 +++--- geotrek/diving/helpers_sync.py | 6 ++- .../migrations/0004_auto_20200228_2153.py | 4 +- geotrek/diving/urls.py | 2 +- geotrek/feedback/urls.py | 2 +- geotrek/flatpages/forms.py | 7 ++- .../migrations/0005_auto_20200228_2150.py | 4 +- geotrek/infrastructure/urls.py | 2 +- geotrek/outdoor/models.py | 3 +- geotrek/outdoor/urls.py | 4 +- .../migrations/0018_auto_20200228_2152.py | 4 +- geotrek/sensitivity/urls.py | 2 +- geotrek/signage/urls.py | 4 +- geotrek/tourism/managers.py | 5 +- .../migrations/0010_auto_20200228_2152.py | 4 +- .../migrations/0033_auto_20220929_0840.py | 2 +- geotrek/tourism/urls.py | 14 +++--- geotrek/trekking/forms.py | 5 +- geotrek/trekking/helpers_sync.py | 14 +++--- .../migrations/0014_auto_20200228_2127.py | 4 +- geotrek/trekking/parsers.py | 30 ++++++------ geotrek/trekking/urls.py | 6 +-- 36 files changed, 161 insertions(+), 136 deletions(-) diff --git a/geotrek/api/management/commands/sync_mobile.py b/geotrek/api/management/commands/sync_mobile.py index e044e7e42c..1cb13547f5 100644 --- a/geotrek/api/management/commands/sync_mobile.py +++ b/geotrek/api/management/commands/sync_mobile.py @@ -1,16 +1,15 @@ import argparse -import logging import filecmp +import logging import os -import stat -from PIL import Image import re import shutil +import stat import tempfile from time import sleep from zipfile import ZipFile -import cairosvg +import cairosvg from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.core.management.base import BaseCommand, CommandError @@ -19,19 +18,21 @@ from django.test.client import RequestFactory from django.utils import translation from django.utils.translation import gettext as _ -from geotrek.common.models import FileType # NOQA +from modeltranslation.utils import build_localized_fieldname +from PIL import Image + +from geotrek.api.mobile.views.common import FlatPageViewSet, SettingsView +from geotrek.api.mobile.views.trekking import TrekViewSet from geotrek.common import models as common_models from geotrek.common.functions import GeometryType +from geotrek.common.helpers_sync import ZipTilesBuilder +from geotrek.common.models import FileType # NOQA from geotrek.flatpages.models import FlatPage from geotrek.tourism import models as tourism_models -from geotrek.trekking import models as trekking_models -from geotrek.api.mobile.views.trekking import TrekViewSet -from geotrek.api.mobile.views.common import FlatPageViewSet, SettingsView -from geotrek.common.helpers_sync import ZipTilesBuilder +from geotrek.tourism import urls # NOQA # Register mapentity models +from geotrek.trekking import models as trekking_models from geotrek.trekking import urls # NOQA -from geotrek.tourism import urls # NOQA - logger = logging.getLogger(__name__) @@ -237,7 +238,7 @@ def close_zip(self, zipfile, name): def sync_flatpage(self, lang): flatpages = FlatPage.objects.order_by('pk').filter(target__in=['mobile', 'all']).filter( - **{'published_{lang}'.format(lang=lang): True}) + **{build_localized_fieldname('published', lang): True}) if self.portal: flatpages = flatpages.filter(Q(portal__name__in=self.portal) | Q(portal=None)) self.sync_json(lang, FlatPageViewSet, 'flatpages', @@ -249,7 +250,7 @@ def sync_flatpage(self, lang): def sync_trekking(self, lang): self.sync_geojson(lang, TrekViewSet, 'treks.geojson', type_view={'get': 'list'}) treks = trekking_models.Trek.objects.annotate(geom_type=GeometryType("geom")).filter(geom_type="LINESTRING").existing().order_by('pk') - treks = treks.filter(**{'published_{lang}'.format(lang=lang): True}) + treks = treks.filter(**{build_localized_fieldname('published', lang): True}) if self.portal: treks = treks.filter(Q(portal__name__in=self.portal) | Q(portal=None)) diff --git a/geotrek/api/tests/test_mobile/test_sync_mobile.py b/geotrek/api/tests/test_mobile/test_sync_mobile.py index 42c1e07c51..5a06290d9b 100644 --- a/geotrek/api/tests/test_mobile/test_sync_mobile.py +++ b/geotrek/api/tests/test_mobile/test_sync_mobile.py @@ -1,17 +1,13 @@ import errno -from io import StringIO - import json -from landez.sources import DownloadError -from unittest import mock import os -from PIL import Image import shutil -from unittest import skipIf import zipfile +from io import StringIO +from unittest import mock, skipIf from django.conf import settings -from django.contrib.gis.geos import MultiLineString, LineString, Point +from django.contrib.gis.geos import LineString, MultiLineString, Point from django.core import management from django.core.management.base import CommandError from django.db.models import Q @@ -19,18 +15,28 @@ from django.test import TestCase from django.test.utils import override_settings from django.utils import translation +from landez.sources import DownloadError +from modeltranslation.utils import build_localized_fieldname +from PIL import Image -from geotrek.common.tests.factories import RecordSourceFactory, TargetPortalFactory, AttachmentFactory from geotrek.common.tests import TranslationResetMixin -from geotrek.common.utils.testdata import get_dummy_uploaded_image_svg, get_dummy_uploaded_image, get_dummy_uploaded_file +from geotrek.common.tests.factories import (AttachmentFactory, + RecordSourceFactory, + TargetPortalFactory) +from geotrek.common.utils.testdata import (get_dummy_uploaded_file, + get_dummy_uploaded_image, + get_dummy_uploaded_image_svg) from geotrek.core.tests.factories import PathFactory -from geotrek.flatpages.tests.factories import FlatPageFactory from geotrek.flatpages.models import FlatPage -from geotrek.trekking.models import Trek, OrderedTrekChild -from geotrek.trekking.tests.factories import TrekFactory, TrekWithPublishedPOIsFactory, PracticeFactory -from geotrek.tourism.tests.factories import (InformationDeskFactory, InformationDeskTypeFactory, - TouristicContentFactory, TouristicEventFactory) +from geotrek.flatpages.tests.factories import FlatPageFactory from geotrek.tourism.models import TouristicEventType +from geotrek.tourism.tests.factories import (InformationDeskFactory, + InformationDeskTypeFactory, + TouristicContentFactory, + TouristicEventFactory) +from geotrek.trekking.models import OrderedTrekChild, Trek +from geotrek.trekking.tests.factories import (PracticeFactory, TrekFactory, + TrekWithPublishedPOIsFactory) class VarTmpTestCase(TestCase): @@ -251,7 +257,7 @@ def test_sync_flatpage(self): with open(os.path.join(os.path.join(settings.TMP_DIR, 'sync_mobile', 'tmp_sync'), lang, 'flatpages.json'), 'r') as f: flatpages = json.load(f) self.assertEqual(len(flatpages), - FlatPage.objects.filter(**{'published_{}'.format(lang): True}).count()) + FlatPage.objects.filter(**{build_localized_fieldname('published', lang): True}).count()) self.assertIn('en/flatpages.json', output.getvalue()) def test_sync_filtering_portal(self): @@ -280,7 +286,7 @@ def test_sync_flatpage_lang(self): with open(os.path.join(os.path.join(settings.TMP_DIR, 'sync_mobile', 'tmp_sync'), lang, 'flatpages.json'), 'r') as f: flatpages = json.load(f) self.assertEqual(len(flatpages), - FlatPage.objects.filter(**{'published_{}'.format(lang): True}).count()) + FlatPage.objects.filter(**{build_localized_fieldname('published', lang): True}).count()) self.assertIn('en/flatpages.json', output.getvalue()) def test_sync_flatpage_content(self): @@ -291,7 +297,7 @@ def test_sync_flatpage_content(self): with open(os.path.join(os.path.join(settings.TMP_DIR, 'sync_mobile', 'tmp_sync'), lang, 'flatpages.json'), 'r') as f: flatpages = json.load(f) self.assertEqual(len(flatpages), - FlatPage.objects.filter(**{'published_{}'.format(lang): True}).count()) + FlatPage.objects.filter(**{build_localized_fieldname('published', lang): True}).count()) self.assertIn('en/flatpages.json', output.getvalue()) @@ -400,7 +406,7 @@ def test_sync_treks(self): with open(os.path.join(os.path.join(settings.TMP_DIR, 'sync_mobile', 'tmp_sync'), lang, 'treks.geojson'), 'r') as f: trek_geojson = json.load(f) self.assertEqual(len(trek_geojson['features']), - Trek.objects.filter(**{'published_{}'.format(lang): True}).count()) + Trek.objects.filter(**{build_localized_fieldname('published', lang): True}).count()) self.assertIn('en/treks.geojson', output.getvalue()) def test_sync_treks_by_pk(self): @@ -426,7 +432,7 @@ def test_sync_treks_with_portal(self): with open(os.path.join(settings.TMP_DIR, 'sync_mobile', 'tmp_sync', lang, 'treks.geojson'), 'r') as f: trek_geojson = json.load(f) self.assertEqual(len(trek_geojson['features']), - Trek.objects.filter(**{'published_{}'.format(lang): True}) + Trek.objects.filter(**{build_localized_fieldname('published', lang): True}) .filter(Q(portal__name__in=(self.portal_a,)) | Q(portal=None)).count()) with open(os.path.join(settings.TMP_DIR, 'sync_mobile', 'tmp_sync', 'en', str(self.trek_1.pk), 'touristic_contents.geojson'), 'r') as f: tc_geojson = json.load(f) @@ -563,7 +569,7 @@ def test_multilinestring(self): with open(os.path.join(os.path.join(settings.TMP_DIR, 'sync_mobile', 'tmp_sync'), lang, 'treks.geojson'), 'r') as f: trek_geojson = json.load(f) self.assertEqual(len(trek_geojson['features']), - Trek.objects.filter(**{'published_{}'.format(lang): True}).count()) + Trek.objects.filter(**{build_localized_fieldname('published', lang): True}).count()) def test_sync_treks_informationdesk_photo_missing(self): os.remove(self.info_desk.photo.path) diff --git a/geotrek/api/v2/filters.py b/geotrek/api/v2/filters.py index 264e2c690e..42507a16d0 100644 --- a/geotrek/api/v2/filters.py +++ b/geotrek/api/v2/filters.py @@ -13,6 +13,7 @@ from django_filters.widgets import CSVWidget from rest_framework.filters import BaseFilterBackend from rest_framework_gis.filters import DistanceToPointFilter, InBBOXFilter +from modeltranslation.utils import build_localized_fieldname from geotrek.tourism.models import TouristicEventOrganizer, TouristicContent, TouristicContentType, TouristicEvent, \ TouristicEventPlace, TouristicEventType @@ -141,13 +142,13 @@ def filter_queryset(self, request, queryset, view): # no language specified. Check for all. q = Q() for lang in settings.MODELTRANSLATION_LANGUAGES: - field_name = 'published_{}'.format(lang.replace('-', '_')) + field_name = build_localized_fieldname('published', lang) if field_name in associated_published_fields: q |= Q(**{field_name: True}) qs = qs.filter(q) else: # one language is specified - field_name = 'published_{}'.format(language.replace('-', '_')) + field_name = build_localized_fieldname('published', language) qs = qs.filter(**{field_name: True}) return qs @@ -991,12 +992,12 @@ def filter_queryset_related_objects_published(self, queryset, request, related_n language = request.GET.get('language') if language: # one language is specified - related_field_name = '{}__published_{}'.format(related_name, language.replace('-', '_')) + related_field_name = '{}__{}'.format(related_name, build_localized_fieldname('published', language)) q &= Q(**{related_field_name: True}) else: # no language specified. Check for all. for lang in settings.MODELTRANSLATION_LANGUAGES: - related_field_name = '{}__published_{}'.format(related_name, lang.replace('-', '_')) + related_field_name = '{}__{}'.format(related_name, build_localized_fieldname('published', lang)) q |= Q(**{related_field_name: True}) q &= optional_query qs = qs.filter(q) diff --git a/geotrek/api/v2/utils.py b/geotrek/api/v2/utils.py index ae6fffd2f9..1f7c4c3960 100644 --- a/geotrek/api/v2/utils.py +++ b/geotrek/api/v2/utils.py @@ -1,4 +1,5 @@ from django.conf import settings +from modeltranslation.utils import build_localized_fieldname def get_translation_or_dict(model_field_name, serializer, instance): @@ -12,13 +13,13 @@ def get_translation_or_dict(model_field_name, serializer, instance): lang = serializer.context.get('request').GET.get('language', 'all') if serializer.context.get('request') else 'all' if lang != 'all': - data = getattr(instance, '{}_{}'.format(model_field_name, lang.replace('-', '_'))) + data = getattr(instance, build_localized_fieldname(model_field_name, lang)) else: data = {} for language in settings.MODELTRANSLATION_LANGUAGES: - data.update({language: getattr(instance, '{}_{}'.format(model_field_name, language.replace('-', '_')), )}) + data.update({language: getattr(instance, build_localized_fieldname(model_field_name, language))}) return data diff --git a/geotrek/api/v2/views/trekking.py b/geotrek/api/v2/views/trekking.py index b40a845f81..cdd311a7b1 100644 --- a/geotrek/api/v2/views/trekking.py +++ b/geotrek/api/v2/views/trekking.py @@ -6,6 +6,7 @@ from rest_framework.decorators import action from rest_framework.generics import get_object_or_404 from rest_framework.response import Response +from modeltranslation.utils import build_localized_fieldname from geotrek.api.v2 import filters as api_filters, serializers as api_serializers, viewsets as api_viewsets from geotrek.api.v2.decorators import cache_response_detail @@ -63,15 +64,15 @@ def filter_published_lang_retrieve(self, request, queryset): # no language specified. Check for all. q = Q() for lang in settings.MODELTRANSLATION_LANGUAGES: - field_name = 'published_{}'.format(lang) + field_name = build_localized_fieldname('published', lang) if field_name in associated_published_fields: - field_name_parent = 'trek_parents__parent__published_{}'.format(lang) + field_name_parent = 'trek_parents__parent__{}'.format(build_localized_fieldname('published', lang)) q |= Q(**{field_name: True}) | Q(**{field_name_parent: True}) qs = qs.filter(q) else: # one language is specified - field_name = 'published_{}'.format(language) - field_name_parent = 'trek_parents__parent__published_{}'.format(language) + field_name = build_localized_fieldname('published', language) + field_name_parent = 'trek_parents__parent__{}'.format(build_localized_fieldname('published', language)) qs = qs.filter(Q(**{field_name: True}) | Q(**{field_name_parent: True})) return qs.distinct() diff --git a/geotrek/common/forms.py b/geotrek/common/forms.py index fd756f1b5c..48310aaf8e 100644 --- a/geotrek/common/forms.py +++ b/geotrek/common/forms.py @@ -18,6 +18,7 @@ from django.utils.text import format_lazy from django.utils.translation import gettext_lazy as _ from mapentity.forms import MapEntityForm, SubmitButton +from modeltranslation.utils import build_localized_fieldname from geotrek.authent.models import (StructureOrNoneRelated, StructureRelated, default_structure) @@ -196,7 +197,7 @@ def check_structure(self, obj, structure, name): @property def any_published(self): """Check if form has published in at least one of the language""" - return any([self.cleaned_data.get(f'published_{language[0]}', False) + return any([self.cleaned_data.get(build_localized_fieldname('published', language[0]), False) for language in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']]) @property @@ -205,7 +206,7 @@ def published_languages(self): """ languages = [language[0] for language in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']] if settings.PUBLISHED_BY_LANG: - return [language for language in languages if self.cleaned_data.get(f'published_{language}', None)] + return [language for language in languages if self.cleaned_data.get(build_localized_fieldname('published', language), None)] else: if self.any_published: return languages @@ -237,12 +238,12 @@ def _get_missing_completeness_fields(self, completeness_fields, msg): if field_required in translated_fields: if self.cleaned_data.get('review') and settings.COMPLETENESS_LEVEL == 'error_on_review': # get field for first language only - field_required_lang = f"{field_required}_{settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES'][0][0]}" + field_required_lang = build_localized_fieldname(field_required, settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES'][0][0]) missing_fields.append(field_required_lang) self.add_error(field_required_lang, msg) else: for language in self.published_languages: - field_required_lang = f'{field_required}_{language}' + field_required_lang = build_localized_fieldname(field_required, language) if not self.cleaned_data.get(field_required_lang): missing_fields.append(field_required_lang) self.add_error(field_required_lang, msg) diff --git a/geotrek/common/management/commands/sync_rando.py b/geotrek/common/management/commands/sync_rando.py index b9e870c8b2..ce06b45348 100644 --- a/geotrek/common/management/commands/sync_rando.py +++ b/geotrek/common/management/commands/sync_rando.py @@ -479,7 +479,7 @@ def handle(self, *args, **options): for language in options['languages'].split(','): if language not in settings.MODELTRANSLATION_LANGUAGES: raise CommandError("Language {lang_n} doesn't exist. Select in these one : {langs}". - format(lang_n=language, langs=settings.MODELTRANSLATION_LANGUAGES)) + format(lang_n=language, langs=list(settings.MODELTRANSLATION_LANGUAGES))) self.languages = options['languages'].split(',') else: self.languages = settings.MODELTRANSLATION_LANGUAGES diff --git a/geotrek/common/management/commands/update_post_migration_languages.py b/geotrek/common/management/commands/update_post_migration_languages.py index 5d42753430..4656f89c44 100644 --- a/geotrek/common/management/commands/update_post_migration_languages.py +++ b/geotrek/common/management/commands/update_post_migration_languages.py @@ -5,6 +5,7 @@ from django.db.models import Q from django.utils.translation import gettext as _ from django.utils import translation +from modeltranslation.utils import build_localized_fieldname from geotrek.common.models import TargetPortal, Label @@ -17,27 +18,26 @@ class Command(BaseCommand): def execute(self, *args, **options): self.stdout.write("Update objects translation after migration from .po files") for lang in settings.MODELTRANSLATION_LANGUAGES: - correct_lang = lang.replace('-', '_') self.stdout.write("Lang : {lang}".format(lang=lang)) with translation.override(lang, deactivate=True): self.stdout.write("TargetPortal") # 'Geotrek Rando' => TargetPortal title TargetPortal.objects.filter( - **{'title_{}'.format(correct_lang): ''} - ).update(**{'title_{}'.format(correct_lang): _('Geotrek Rando')}) + **{build_localized_fieldname('title', lang): ''} + ).update(**{build_localized_fieldname('title', lang): _('Geotrek Rando')}) # 'Geotrek is a web app ...' => TargetPortal description TargetPortal.objects.filter( - **{'description_{}'.format(correct_lang): ''} + **{build_localized_fieldname('description', lang): ''} ).update( - **{'description_{}'.format(correct_lang): _('Geotrek is a web app allowing you to prepare your ' - 'next trekking trip !')}) + **{build_localized_fieldname('description', lang): _('Geotrek is a web app allowing you to prepare your ' + 'next trekking trip !')}) self.stdout.write("Label is park centered") Label.objects.filter(pk=1).filter( - Q(**{'name_{}'.format(correct_lang): ''}) | Q(**{'name_{}'.format(correct_lang): None}) - ).update(**{'name_{}'.format(correct_lang): _('Is in the midst of the park')}) + Q(**{build_localized_fieldname('name', lang): ''}) | Q(**{build_localized_fieldname('name', lang): None}) + ).update(**{build_localized_fieldname('name', lang): _('Is in the midst of the park')}) Label.objects.filter(pk=1).filter( - Q(**{'advice_{}'.format(correct_lang): ''}) | Q(**{'advice_{}'.format(correct_lang): None}) - ).update(**{'advice_{}'.format(correct_lang): _('The national park is an unrestricted natural area but ' - 'subjected to regulations which must be known ' - 'by all visitors.')}) + Q(**{build_localized_fieldname('advice', lang): ''}) | Q(**{build_localized_fieldname('advice', lang): None}) + ).update(**{build_localized_fieldname('advice', lang): _('The national park is an unrestricted natural area but ' + 'subjected to regulations which must be known ' + 'by all visitors.')}) self.stdout.write("Done.") diff --git a/geotrek/common/migrations/0008_auto_20200228_1830.py b/geotrek/common/migrations/0008_auto_20200228_1830.py index 319b221169..5dd59a1aa3 100644 --- a/geotrek/common/migrations/0008_auto_20200228_1830.py +++ b/geotrek/common/migrations/0008_auto_20200228_1830.py @@ -17,10 +17,10 @@ def forward(apps, schema_editor): for lang in settings.MODELTRANSLATION_LANGUAGES: for model, old, new in FIELDS: cursor.execute( - "SELECT 1 FROM information_schema.columns WHERE table_name='common_{}' AND column_name='{}_{}'".format(model, old, lang) + "SELECT 1 FROM information_schema.columns WHERE table_name='common_{}' AND column_name='{}_{}'".format(model, old, lang.replace('-', '_')) ) if cursor.fetchone(): - cursor.execute('ALTER TABLE common_{} RENAME {}_{} TO {}_{}'.format(model, old, lang, new, lang)) + cursor.execute('ALTER TABLE common_{} RENAME {}_{} TO {}_{}'.format(model, old, lang.replace('-', '_'), new, lang.replace('-', '_'))) class Migration(migrations.Migration): diff --git a/geotrek/common/mixins/models.py b/geotrek/common/mixins/models.py index 813cc46361..a39bccc72f 100644 --- a/geotrek/common/mixins/models.py +++ b/geotrek/common/mixins/models.py @@ -25,6 +25,7 @@ from geotrek.common.utils import classproperty, logger from mapentity.models import MapEntityMixin +from modeltranslation.utils import build_localized_fieldname class CheckBoxActionMixin: @@ -288,7 +289,7 @@ def any_published(self): return self.published for language in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']: - if getattr(self, 'published_%s' % language[0], False): + if getattr(self, build_localized_fieldname('published', language[0]), False): return True return False @@ -298,7 +299,7 @@ def published_status(self): status = [] for language in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']: if settings.PUBLISHED_BY_LANG: - published = getattr(self, 'published_%s' % language[0], None) or False + published = getattr(self, build_localized_fieldname('published', language[0]), None) or False else: published = self.published status.append({ @@ -313,7 +314,7 @@ def published_langs(self): """ Returns languages in which the object is published. """ langs = [language[0] for language in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']] if settings.PUBLISHED_BY_LANG: - return [language for language in langs if getattr(self, 'published_%s' % language, None)] + return [language for language in langs if getattr(self, build_localized_fieldname('published', language), None)] elif self.published: return langs else: diff --git a/geotrek/common/mixins/views.py b/geotrek/common/mixins/views.py index e180d11973..2f3f063bd2 100644 --- a/geotrek/common/mixins/views.py +++ b/geotrek/common/mixins/views.py @@ -11,6 +11,7 @@ from django.views import static from mapentity import views as mapentity_views from mapentity.helpers import suffix_for +from modeltranslation.utils import build_localized_fieldname from pdfimpose import PageList from geotrek.common.models import TargetPortal, FileType, Attachment @@ -182,7 +183,7 @@ def get_context_data(self, **kwargs): context['FACEBOOK_IMAGE'] = urljoin(self.request.GET['rando_url'], target_portal.facebook_image_url) context['FACEBOOK_IMAGE_WIDTH'] = target_portal.facebook_image_width context['FACEBOOK_IMAGE_HEIGHT'] = target_portal.facebook_image_height - context['META_TITLE'] = getattr(target_portal, 'title_{}'.format(lang)) + context['META_TITLE'] = getattr(target_portal, build_localized_fieldname('title', lang)) except TargetPortal.DoesNotExist: pass return context diff --git a/geotrek/common/parsers.py b/geotrek/common/parsers.py index d7e6545c00..6e5e580290 100644 --- a/geotrek/common/parsers.py +++ b/geotrek/common/parsers.py @@ -36,6 +36,7 @@ from django.utils.encoding import force_str from django.conf import settings from paperclip.models import attachment_upload, random_suffix_regexp +from modeltranslation.utils import build_localized_fieldname from geotrek.authent.models import default_structure from geotrek.common.models import FileType, Attachment, License @@ -260,7 +261,7 @@ def parse_translation_field(self, dst, src, val): old_values = {} # We keep every old values for each langs to get tracability during filter or apply filter for lang in settings.MODELTRANSLATION_LANGUAGES: - dst_field_lang = '{field}_{lang}'.format(field=dst, lang=lang) + dst_field_lang = build_localized_fieldname(dst, lang) old_values[lang] = getattr(self.obj, dst_field_lang) # If during filter, the traduction of the field has been changed # we can still check if this value has been changed @@ -270,7 +271,7 @@ def parse_translation_field(self, dst, src, val): val_default_language = self.apply_filter(dst, src, val) for lang in settings.MODELTRANSLATION_LANGUAGES: - dst_field_lang = '{field}_{lang}'.format(field=dst, lang=lang) + dst_field_lang = build_localized_fieldname(dst, lang) new_value = getattr(self.obj, dst_field_lang) old_value = old_values[lang] # Field not translated, use same val for all translated @@ -308,7 +309,7 @@ def parse_field(self, row, dst, src, updated, non_field): updated.append(dst) if dst in self.translated_fields: for lang in settings.MODELTRANSLATION_LANGUAGES: - updated.append('{field}_{lang}'.format(field=dst, lang=lang)) + updated.append(build_localized_fieldname(dst, lang)) def parse_fields(self, row, fields, non_field=False): updated = [] diff --git a/geotrek/common/tests/test_sync.py b/geotrek/common/tests/test_sync.py index c1b70a920d..fe97383f69 100644 --- a/geotrek/common/tests/test_sync.py +++ b/geotrek/common/tests/test_sync.py @@ -163,7 +163,7 @@ def test_fail_url_ftp(self): def test_language_not_in_db(self): with self.assertRaisesRegex(CommandError, - r"Language cat doesn't exist. Select in these one : \('en', 'es', 'fr', 'it'\)"): + r"Language cat doesn't exist. Select in these one : \['en', 'es', 'fr', 'it'\]"): management.call_command('sync_rando', os.path.join(settings.TMP_DIR, 'sync_rando', 'tmp_sync'), url='http://localhost:8000', skip_tiles=True, languages='cat', verbosity=2) diff --git a/geotrek/common/urls.py b/geotrek/common/urls.py index 8e08546a6b..44d68f579e 100644 --- a/geotrek/common/urls.py +++ b/geotrek/common/urls.py @@ -9,7 +9,7 @@ class LangConverter(converters.StringConverter): - regex = "[a-z\-]{2,7}" + regex = "[a-z]{2}(-[a-z]{2,4})?" # noqa register_converter(LangConverter, "lang") diff --git a/geotrek/common/views.py b/geotrek/common/views.py index c605e604f4..73c8962f11 100644 --- a/geotrek/common/views.py +++ b/geotrek/common/views.py @@ -41,6 +41,7 @@ from mapentity.helpers import api_bbox from mapentity.registry import app_settings, registry from mapentity.views import MapEntityList +from modeltranslation.utils import build_localized_fieldname from paperclip import settings as settings_paperclip from paperclip.views import _handle_attachment_form from rest_framework import mixins @@ -95,29 +96,29 @@ def get_context_data(self, **kwargs): if portal: try: target_portal = TargetPortal.objects.get(name=portal) - context['META_DESCRIPTION'] = getattr(target_portal, 'description_{}'.format(lang)) + context['META_DESCRIPTION'] = getattr(target_portal, build_localized_fieldname('description', lang)) except TargetPortal.DoesNotExist: pass if 'geotrek.trekking' in settings.INSTALLED_APPS: from geotrek.trekking.models import Trek context['treks'] = Trek.objects.existing().order_by('pk').filter( - Q(**{'published_{lang}'.format(lang=lang): True}) - | Q(**{'trek_parents__parent__published_{lang}'.format(lang=lang): True, + Q(**{build_localized_fieldname('published', lang): True}) + | Q(**{'trek_parents__parent__{published_lang}'.format(published_lang=build_localized_fieldname('published', lang)): True, 'trek_parents__parent__deleted': False}) ) if 'geotrek.tourism' in settings.INSTALLED_APPS: from geotrek.tourism.models import TouristicContent, TouristicEvent context['contents'] = TouristicContent.objects.existing().order_by('pk').filter( - **{'published_{lang}'.format(lang=lang): True} + **{build_localized_fieldname('published', lang): True} ) context['events'] = TouristicEvent.objects.existing().order_by('pk').filter( - **{'published_{lang}'.format(lang=lang): True} + **{build_localized_fieldname('published', lang): True} ) if 'geotrek.diving' in settings.INSTALLED_APPS: from geotrek.diving.models import Dive context['dives'] = Dive.objects.existing().order_by('pk').filter( - **{'published_{lang}'.format(lang=lang): True} + **{build_localized_fieldname('published', lang): True} ) return context diff --git a/geotrek/diving/helpers_sync.py b/geotrek/diving/helpers_sync.py index bbfa9c9b40..c4a256dbe4 100644 --- a/geotrek/diving/helpers_sync.py +++ b/geotrek/diving/helpers_sync.py @@ -1,10 +1,14 @@ from django.conf import settings from django.db.models import Q + +from modeltranslation.utils import build_localized_fieldname + import os from geotrek.diving import models from geotrek.diving import views as diving_views + if 'geotrek.sensitivity' in settings.INSTALLED_APPS: from geotrek.sensitivity import views as sensitivity_views if 'geotrek.tourism' in settings.INSTALLED_APPS: @@ -21,7 +25,7 @@ def sync(self, lang): self.global_sync.sync_geojson(lang, diving_views.DiveAPIViewSet, 'dives.geojson') dives = models.Dive.objects.existing().order_by('pk') - dives = dives.filter(**{'published_{lang}'.format(lang=lang): True}) + dives = dives.filter(**{build_localized_fieldname('published', lang): True}) if self.global_sync.source: dives = dives.filter(source__name__in=self.global_sync.source) diff --git a/geotrek/diving/migrations/0004_auto_20200228_2153.py b/geotrek/diving/migrations/0004_auto_20200228_2153.py index df13bc4f68..32f9c2dfc2 100644 --- a/geotrek/diving/migrations/0004_auto_20200228_2153.py +++ b/geotrek/diving/migrations/0004_auto_20200228_2153.py @@ -25,10 +25,10 @@ def forward(apps, schema_editor): for lang in settings.MODELTRANSLATION_LANGUAGES: for model, old, new in FIELDS: cursor.execute( - "SELECT 1 FROM information_schema.columns WHERE table_name='diving_{}' AND column_name='{}_{}'".format(model, old, lang) + "SELECT 1 FROM information_schema.columns WHERE table_name='diving_{}' AND column_name='{}_{}'".format(model, old, lang.replace('-', '_')) ) if cursor.fetchone(): - cursor.execute('ALTER TABLE diving_{} RENAME {}_{} TO {}_{}'.format(model, old, lang, new, lang)) + cursor.execute('ALTER TABLE diving_{} RENAME {}_{} TO {}_{}'.format(model, old, lang.replace('-', '_'), new, lang.replace('-', '_'))) class Migration(migrations.Migration): diff --git a/geotrek/diving/urls.py b/geotrek/diving/urls.py index 9bc708fa66..f495df6009 100644 --- a/geotrek/diving/urls.py +++ b/geotrek/diving/urls.py @@ -34,7 +34,7 @@ def get_queryset(self): router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/dives', DiveAPIViewSet, basename='dive') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/dives', DiveAPIViewSet, basename='dive') urlpatterns += router.urls urlpatterns += registry.register(models.Dive, DiveEntityOptions, menu=settings.DIVE_MODEL_ENABLED) diff --git a/geotrek/feedback/urls.py b/geotrek/feedback/urls.py index 64199ae9b4..4a9edc087f 100644 --- a/geotrek/feedback/urls.py +++ b/geotrek/feedback/urls.py @@ -17,6 +17,6 @@ path('api//feedback/options.json', FeedbackOptionsView.as_view(), name="options_json"), ] router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/reports', ReportAPIViewSet, basename='report') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/reports', ReportAPIViewSet, basename='report') urlpatterns += router.urls urlpatterns += registry.register(feedback_models.Report, menu=settings.REPORT_MODEL_ENABLED) diff --git a/geotrek/flatpages/forms.py b/geotrek/flatpages/forms.py index d2c3abb96e..511394a858 100644 --- a/geotrek/flatpages/forms.py +++ b/geotrek/flatpages/forms.py @@ -1,5 +1,4 @@ from django import forms -from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.utils.html import strip_tags @@ -7,8 +6,8 @@ from geotrek.common.forms import CommonForm from geotrek.common.models import Attachment, FileType from geotrek.flatpages.models import FlatPage -if 'modeltranslation' in settings.INSTALLED_APPS: - from modeltranslation.settings import AVAILABLE_LANGUAGES +from modeltranslation.settings import AVAILABLE_LANGUAGES +from modeltranslation.utils import build_localized_fieldname class FlatPageForm(CommonForm): @@ -53,7 +52,7 @@ def clean(self): # Test if HTML was filled # Use strip_tags() to catch empty tags (e.g. ``

``) - html_content = cleaned_data.get('content_{}'.format(lang), None) or '' + html_content = cleaned_data.get(build_localized_fieldname('content', lang), None) or '' if external_url and external_url.strip() and strip_tags(html_content): raise ValidationError(_('Choose between external URL and HTML content')) diff --git a/geotrek/flatpages/migrations/0005_auto_20200228_2150.py b/geotrek/flatpages/migrations/0005_auto_20200228_2150.py index 51644e3f5d..085d8cd24f 100644 --- a/geotrek/flatpages/migrations/0005_auto_20200228_2150.py +++ b/geotrek/flatpages/migrations/0005_auto_20200228_2150.py @@ -19,10 +19,10 @@ def forward(apps, schema_editor): for lang in settings.MODELTRANSLATION_LANGUAGES: for model, old, new in FIELDS: cursor.execute( - "SELECT 1 FROM information_schema.columns WHERE table_name='flatpages_{}' AND column_name='{}_{}'".format(model, old, lang) + "SELECT 1 FROM information_schema.columns WHERE table_name='flatpages_{}' AND column_name='{}_{}'".format(model, old, lang.replace('-', '_')) ) if cursor.fetchone(): - cursor.execute('ALTER TABLE flatpages_{} RENAME {}_{} TO {}_{}'.format(model, old, lang, new, lang)) + cursor.execute('ALTER TABLE flatpages_{} RENAME {}_{} TO {}_{}'.format(model, old, lang.replace('-', '_'), new, lang.replace('-', '_'))) class Migration(migrations.Migration): diff --git a/geotrek/infrastructure/urls.py b/geotrek/infrastructure/urls.py index 46ab316589..2010b4c0da 100644 --- a/geotrek/infrastructure/urls.py +++ b/geotrek/infrastructure/urls.py @@ -18,7 +18,7 @@ router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/infrastructures', InfrastructureAPIViewSet, basename='infrastructrure') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/infrastructures', InfrastructureAPIViewSet, basename='infrastructrure') urlpatterns += router.urls urlpatterns += [ diff --git a/geotrek/outdoor/models.py b/geotrek/outdoor/models.py index b66cfaf62b..b2301b4a70 100644 --- a/geotrek/outdoor/models.py +++ b/geotrek/outdoor/models.py @@ -12,6 +12,7 @@ from django.utils.html import escape from django.utils.translation import gettext_lazy as _ from geotrek.common.signals import log_cascade_deletion +from modeltranslation.utils import build_localized_fieldname from mptt.models import MPTTModel, TreeForeignKey from geotrek.altimetry.models import AltimetryMixin as BaseAltimetryMixin @@ -249,7 +250,7 @@ def published_children(self): return self.children.filter(published=True) q = Q() for lang in settings.MODELTRANSLATION_LANGUAGES: - q |= Q(**{'published_{}'.format(lang): True}) + q |= Q(**{build_localized_fieldname('published', lang): True}) return self.children.filter(q) @property diff --git a/geotrek/outdoor/urls.py b/geotrek/outdoor/urls.py index e2cbe683cf..6173d35e33 100644 --- a/geotrek/outdoor/urls.py +++ b/geotrek/outdoor/urls.py @@ -12,8 +12,8 @@ router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/courses', outdoor_views.CourseAPIViewSet, basename='course') -router.register(r'^api/(?P[a-z]{2})/sites', outdoor_views.SiteAPIViewSet, basename='site') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/courses', outdoor_views.CourseAPIViewSet, basename='course') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/sites', outdoor_views.SiteAPIViewSet, basename='site') class SiteEntityOptions(PublishableEntityOptions): diff --git a/geotrek/sensitivity/migrations/0018_auto_20200228_2152.py b/geotrek/sensitivity/migrations/0018_auto_20200228_2152.py index 03320bc006..5ee65baed4 100644 --- a/geotrek/sensitivity/migrations/0018_auto_20200228_2152.py +++ b/geotrek/sensitivity/migrations/0018_auto_20200228_2152.py @@ -17,10 +17,10 @@ def forward(apps, schema_editor): for lang in settings.MODELTRANSLATION_LANGUAGES: for model, old, new in FIELDS: cursor.execute( - "SELECT 1 FROM information_schema.columns WHERE table_name='sensitivity_{}' AND column_name='{}_{}'".format(model, old, lang) + "SELECT 1 FROM information_schema.columns WHERE table_name='sensitivity_{}' AND column_name='{}_{}'".format(model, old, lang.replace('-', '_')) ) if cursor.fetchone(): - cursor.execute('ALTER TABLE sensitivity_{} RENAME {}_{} TO {}_{}'.format(model, old, lang, new, lang)) + cursor.execute('ALTER TABLE sensitivity_{} RENAME {}_{} TO {}_{}'.format(model, old, lang.replace('-', '_'), new, lang.replace('-', '_'))) class Migration(migrations.Migration): diff --git a/geotrek/sensitivity/urls.py b/geotrek/sensitivity/urls.py index 4f9e53af05..c8b567049f 100644 --- a/geotrek/sensitivity/urls.py +++ b/geotrek/sensitivity/urls.py @@ -31,7 +31,7 @@ def get_queryset(self): ] router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/sensitiveareas', views.SensitiveAreaAPIViewSet, basename='sensitivearea') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/sensitiveareas', views.SensitiveAreaAPIViewSet, basename='sensitivearea') urlpatterns += router.urls if 'geotrek.trekking' in settings.INSTALLED_APPS: diff --git a/geotrek/signage/urls.py b/geotrek/signage/urls.py index e22e0ee9aa..c594d1f5d6 100644 --- a/geotrek/signage/urls.py +++ b/geotrek/signage/urls.py @@ -17,11 +17,11 @@ router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/signages', SignageAPIViewSet, basename='signage') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/signages', SignageAPIViewSet, basename='signage') if settings.BLADE_ENABLED: urlpatterns += registry.register(models.Blade, menu=False) - router.register(r'^api/(?P[a-z]{2})/blades', BladeAPIViewSet, basename='blade') + router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/blades', BladeAPIViewSet, basename='blade') urlpatterns += router.urls diff --git a/geotrek/tourism/managers.py b/geotrek/tourism/managers.py index 15d85941d0..35938dea22 100644 --- a/geotrek/tourism/managers.py +++ b/geotrek/tourism/managers.py @@ -1,6 +1,7 @@ from django.conf import settings from django.db.models import Q from modeltranslation.manager import MultilingualManager +from modeltranslation.utils import build_localized_fieldname from geotrek.common.mixins.managers import NoDeleteManager, ProviderChoicesMixin @@ -35,12 +36,12 @@ def has_content_published_not_deleted_in_list(self, list_index, category=None, p q_category = Q(**{category_field_name: category}) if language: - published_field_name = f"contents{i}__published_{language.replace('-', '_')}" + published_field_name = f"contents{i}__{build_localized_fieldname('published', language)}" q_lang = Q(**{published_field_name: True}) else: q_lang = Q() for lang in settings.MODELTRANSLATION_LANGUAGES: - published_field_name = f"contents{i}__published_{lang.replace('-', '_')}" + published_field_name = f"contents{i}__{build_localized_fieldname('published', lang)}" q_lang |= Q(**{published_field_name: True}) deleted_field_name = f"contents{i}__deleted" diff --git a/geotrek/tourism/migrations/0010_auto_20200228_2152.py b/geotrek/tourism/migrations/0010_auto_20200228_2152.py index 8e76bf2137..22dbfe679f 100644 --- a/geotrek/tourism/migrations/0010_auto_20200228_2152.py +++ b/geotrek/tourism/migrations/0010_auto_20200228_2152.py @@ -32,10 +32,10 @@ def forward(apps, schema_editor): for lang in settings.MODELTRANSLATION_LANGUAGES: for model, old, new in FIELDS: cursor.execute( - "SELECT 1 FROM information_schema.columns WHERE table_name='tourism_{}' AND column_name='{}_{}'".format(model, old, lang) + "SELECT 1 FROM information_schema.columns WHERE table_name='tourism_{}' AND column_name='{}_{}'".format(model, old, lang.replace('-', '_')) ) if cursor.fetchone(): - cursor.execute('ALTER TABLE tourism_{} RENAME {}_{} TO {}_{}'.format(model, old, lang, new, lang)) + cursor.execute('ALTER TABLE tourism_{} RENAME {}_{} TO {}_{}'.format(model, old, lang.replace('-', '_'), new, lang.replace('-', '_'))) class Migration(migrations.Migration): diff --git a/geotrek/tourism/migrations/0033_auto_20220929_0840.py b/geotrek/tourism/migrations/0033_auto_20220929_0840.py index 3a7ff9cb9e..eb3a78e190 100644 --- a/geotrek/tourism/migrations/0033_auto_20220929_0840.py +++ b/geotrek/tourism/migrations/0033_auto_20220929_0840.py @@ -16,7 +16,7 @@ def clean_participants_number(apps, schema_editor): new_info = f"Participants: {participant_number}" for lang in settings.MODELTRANSLATION_LANGUAGES: cursor.execute( - "UPDATE tourism_touristicevent SET practical_info_{} = practical_info_{} || ' ' || %s WHERE id='{}';".format(lang, lang, id), [new_info] + "UPDATE tourism_touristicevent SET practical_info_{} = practical_info_{} || ' ' || %s WHERE id='{}';".format(lang.replace('-', '_'), lang.replace('-', '_'), id), [new_info] ) qs.update( participant_number='' diff --git a/geotrek/tourism/urls.py b/geotrek/tourism/urls.py index 71400c9408..e0bc694d0d 100644 --- a/geotrek/tourism/urls.py +++ b/geotrek/tourism/urls.py @@ -14,11 +14,11 @@ app_name = 'tourism' urlpatterns = [ - re_path(r'^api/(?P\w\w)/information_desks\.geojson$', tourism_views.InformationDeskViewSet.as_view({'get': 'list'}), name="information_desk_geojson"), - re_path(r'^api/(?P\w\w)/information_desks-(?P\d+)\.geojson$', tourism_views.InformationDeskViewSet.as_view({'get': 'list'})), - re_path(r'^api/(?P\w\w)/treks/(?P\d+)/information_desks.geojson$', tourism_views.TrekInformationDeskViewSet.as_view({'get': 'list'}), name="trek_information_desk_geojson"), - re_path(r'^api/(?P\w\w)/treks/(?P\d+)/touristicevents\.geojson$', tourism_views.TrekTouristicEventViewSet.as_view({'get': 'list'}), name="trek_events_geojson"), - re_path(r'^api/(?P\w\w)/treks/(?P\d+)/touristiccontents\.geojson$', tourism_views.TrekTouristicContentViewSet.as_view({'get': 'list'}), name="trek_contents_geojson"), + re_path(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/information_desks.geojson$', tourism_views.InformationDeskViewSet.as_view({'get': 'list'}), name="information_desk_geojson"), + re_path(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/information_desks-(?P\d+)\.geojson$', tourism_views.InformationDeskViewSet.as_view({'get': 'list'})), + re_path(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/treks/(?P\d+)/information_desks.geojson$', tourism_views.TrekInformationDeskViewSet.as_view({'get': 'list'}), name="trek_information_desk_geojson"), + re_path(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/treks/(?P\d+)/touristicevents\.geojson$', tourism_views.TrekTouristicEventViewSet.as_view({'get': 'list'}), name="trek_events_geojson"), + re_path(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/treks/(?P\d+)/touristiccontents\.geojson$', tourism_views.TrekTouristicContentViewSet.as_view({'get': 'list'}), name="trek_contents_geojson"), path('api//touristiccategories.json', tourism_views.TouristicCategoryView.as_view(), name="touristic_categories_json"), path('api//touristiccontents//meta.html', tourism_views.TouristicContentMeta.as_view(), name="touristiccontent_meta"), path('api//touristicevents//meta.html', tourism_views.TouristicEventMeta.as_view(), name="touristicevent_meta"), @@ -44,8 +44,8 @@ class TouristicEventEntityOptions(PublishableEntityOptions): router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/touristiccontents', TouristicContentAPIViewSet, basename='touristiccontent') -router.register(r'^api/(?P[a-z]{2})/touristicevents', TouristicEventAPIViewSet, basename='touristicevent') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/touristiccontents', TouristicContentAPIViewSet, basename='touristiccontent') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/touristicevents', TouristicEventAPIViewSet, basename='touristicevent') urlpatterns += router.urls diff --git a/geotrek/trekking/forms.py b/geotrek/trekking/forms.py index 3a401f230c..5c2568797c 100644 --- a/geotrek/trekking/forms.py +++ b/geotrek/trekking/forms.py @@ -12,6 +12,7 @@ from crispy_forms.layout import Layout, Submit, HTML, Div, Fieldset from mapentity.forms import TranslatedModelForm from mapentity.widgets import SelectMultipleWithPop, MapWidget +from modeltranslation.utils import build_localized_fieldname from geotrek.common.forms import CommonForm from geotrek.core.forms import TopologyForm @@ -188,7 +189,7 @@ def __init__(self, *args, **kwargs): self.fields['web_links'].widget = SelectMultipleWithPop(choices=self.fields['web_links'].choices, add_url=WebLink.get_add_url()) # Make sure (force) that name is required, in default language only - self.fields['name_%s' % settings.LANGUAGE_CODE.replace('-', '_')].required = True + self.fields[build_localized_fieldname('name', settings.LANGUAGE_CODE)].required = True if not settings.TREK_POINTS_OF_REFERENCE_ENABLED: self.fields.pop('points_reference') @@ -419,7 +420,7 @@ def __init__(self, *args, **kwargs): # Main form layout # Adds every name field explicitly (name_fr, name_en, ...) self.helper.form_class = 'form-horizontal' - arg_list = [f'name_{language[0]}' for language in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']] + arg_list = [build_localized_fieldname('name', language[0]) for language in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']] arg_list += ['url', 'category', FormActions( HTML('%s' % _("Cancel")), Submit('save_changes', _('Create'), css_class="btn-primary"), diff --git a/geotrek/trekking/helpers_sync.py b/geotrek/trekking/helpers_sync.py index e07e0a9825..cea9f9ff36 100644 --- a/geotrek/trekking/helpers_sync.py +++ b/geotrek/trekking/helpers_sync.py @@ -1,12 +1,12 @@ -from django.conf import settings -from django.db.models import Q - import os from zipfile import ZipFile +from django.conf import settings +from django.db.models import Q +from modeltranslation.utils import build_localized_fieldname + from geotrek.common import views as common_views -from geotrek.trekking import views -from geotrek.trekking import models +from geotrek.trekking import models, views if 'geotrek.tourism' in settings.INSTALLED_APPS: from geotrek.tourism import views as tourism_views @@ -31,8 +31,8 @@ def sync(self, lang): treks = models.Trek.objects.existing().order_by('pk') treks = treks.filter( - Q(**{'published_{lang}'.format(lang=lang): True}) - | Q(**{'trek_parents__parent__published_{lang}'.format(lang=lang): True, + Q(**{build_localized_fieldname('published', lang): True}) + | Q(**{'trek_parents__parent__{published_lang}'.format(published_lang=build_localized_fieldname('published', lang)): True, 'trek_parents__parent__deleted': False}) ) if self.global_sync.source: diff --git a/geotrek/trekking/migrations/0014_auto_20200228_2127.py b/geotrek/trekking/migrations/0014_auto_20200228_2127.py index 1e21fc79f4..b60cc58630 100644 --- a/geotrek/trekking/migrations/0014_auto_20200228_2127.py +++ b/geotrek/trekking/migrations/0014_auto_20200228_2127.py @@ -36,10 +36,10 @@ def forward(apps, schema_editor): for lang in settings.MODELTRANSLATION_LANGUAGES: for model, old, new in FIELDS: cursor.execute( - "SELECT 1 FROM information_schema.columns WHERE table_name='trekking_{}' AND column_name='{}_{}'".format(model, old, lang) + "SELECT 1 FROM information_schema.columns WHERE table_name='trekking_{}' AND column_name='{}_{}'".format(model, old, lang.replace('-', '_')) ) if cursor.fetchone(): - cursor.execute('ALTER TABLE trekking_{} RENAME {}_{} TO {}_{}'.format(model, old, lang, new, lang)) + cursor.execute('ALTER TABLE trekking_{} RENAME {}_{} TO {}_{}'.format(model, old, lang.replace('-', '_'), new, lang.replace('-', '_'))) class Migration(migrations.Migration): diff --git a/geotrek/trekking/parsers.py b/geotrek/trekking/parsers.py index 5020d4200d..5ce1b8a46f 100644 --- a/geotrek/trekking/parsers.py +++ b/geotrek/trekking/parsers.py @@ -1,23 +1,27 @@ -from datetime import date, timedelta -from decimal import Decimal import io import json -from collections import defaultdict import re -from tempfile import NamedTemporaryFile import zipfile +from collections import defaultdict +from datetime import date, timedelta +from decimal import Decimal +from tempfile import NamedTemporaryFile from django.conf import settings from django.contrib.gis.gdal import DataSource -from django.contrib.gis.geos import Point, GEOSGeometry, MultiLineString -from django.utils.translation import gettext as _, get_language +from django.contrib.gis.geos import GEOSGeometry, MultiLineString, Point +from django.utils.translation import get_language +from django.utils.translation import gettext as _ +from modeltranslation.utils import build_localized_fieldname from geotrek.common.models import Label, Theme -from geotrek.common.parsers import ( - ShapeParser, AttachmentParserMixin, GeotrekParser, GlobalImportError, RowImportError, Parser, ApidaeBaseParser -) +from geotrek.common.parsers import (ApidaeBaseParser, AttachmentParserMixin, + GeotrekParser, GlobalImportError, Parser, + RowImportError, ShapeParser) from geotrek.core.models import Path, Topology -from geotrek.trekking.models import OrderedTrekChild, POI, Service, Trek, DifficultyLevel, TrekNetwork, Accessibility +from geotrek.trekking.models import (POI, Accessibility, DifficultyLevel, + OrderedTrekChild, Service, Trek, + TrekNetwork) class DurationParserMixin: @@ -333,7 +337,7 @@ def _expand_fields_mapping_with_translation_fields(self): src = self.fields[translated_field] del self.fields[translated_field] for lang in settings.MODELTRANSLATION_LANGUAGES: - self.fields[f'{translated_field}_{lang}'] = f'{src}.{self.apidae_translation_prefix}{lang.capitalize()}' + self.fields[build_localized_fieldname(translated_field, lang)] = f'{src}.{self.apidae_translation_prefix}{lang.capitalize()}' @classmethod def _get_default_translation_src(cls): @@ -1082,12 +1086,12 @@ def __init__(self, *args, **kwargs): def _add_multi_languages_fields_mapping(self): self.fields = { - f'{self.name_field}_{lang}': f'libelle{lang.capitalize()}' + build_localized_fieldname(self.name_field, lang): f'libelle{lang.capitalize()}' for lang in settings.MODELTRANSLATION_LANGUAGES } def _set_eid_fieldname(self): - self.eid = f'{self.name_field}_{settings.MODELTRANSLATION_DEFAULT_LANGUAGE}' + self.eid = build_localized_fieldname(self.name_field, settings.MODELTRANSLATION_DEFAULT_LANGUAGE) @property def items(self): diff --git a/geotrek/trekking/urls.py b/geotrek/trekking/urls.py index 31fe204a5b..bd74cfe20e 100644 --- a/geotrek/trekking/urls.py +++ b/geotrek/trekking/urls.py @@ -53,9 +53,9 @@ class ServiceEntityOptions(MapEntityOptions): router = DefaultRouter(trailing_slash=False) -router.register(r'^api/(?P[a-z]{2})/treks', TrekAPIViewSet, basename='trek') -router.register(r'^api/(?P[a-z]{2})/pois', POIAPIViewSet, basename='poi') -router.register(r'^api/(?P[a-z]{2})/services', ServiceAPIViewSet, basename='service') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/treks', TrekAPIViewSet, basename='trek') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/pois', POIAPIViewSet, basename='poi') +router.register(r'^api/(?P[a-z]{2}(-[a-z]{2,4})?)/services', ServiceAPIViewSet, basename='service') urlpatterns += router.urls urlpatterns += registry.register(models.Trek, TrekEntityOptions, menu=settings.TREKKING_MODEL_ENABLED)