We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Traductions sur le "hover" des filtres
# Résumé

Dans l'interface, tout les filtres qui utilisent le widget `OneLineRangeWidget` ne sont pas traduit.

# Reproduction

- Passé geotrek admin en anglais
- Remplir certains filtres (ceux avec min / max)
- Fermer la fenêtre des filtres
- Placer la souris sur le bouton `Filter`

On pourra observer certains éléments traduits et d'autre non.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `geotrek/common/filters/__init__.py`
Content:
```
1 from django.utils.translation import gettext_lazy as _
2 from django_filters import ModelMultipleChoiceFilter, RangeFilter
3 from mapentity.filters import MapEntityFilterSet
4 
5 from geotrek.common.filters.fields import ComaSeparatedMultipleModelChoiceField, OneLineRangeField
6 from geotrek.common.models import HDViewPoint
7 
8 
9 class ComaSeparatedMultipleModelChoiceFilter(ModelMultipleChoiceFilter):
10     field_class = ComaSeparatedMultipleModelChoiceField
11 
12 
13 class OptionalRangeFilter(RangeFilter):
14     field_class = OneLineRangeField
15 
16     def __init__(self, *args, **kwargs):
17         super().__init__(*args, **kwargs)
18         self.field.fields[0].label = _('min %s') % self.field.label
19         self.field.fields[1].label = _('max %s') % self.field.label
20 
21 
22 class RightFilter(ModelMultipleChoiceFilter):
23     model = None
24     queryset = None
25 
26     def __init__(self, *args, **kwargs):
27         kwargs.setdefault('queryset', self.get_queryset())
28         super().__init__(*args, **kwargs)
29         self.field.widget.attrs['class'] = self.field.widget.attrs.get('class', '') + 'right-filter'
30         self.field.widget.renderer = None
31 
32     def get_queryset(self, request=None):
33         if self.queryset is not None:
34             return self.queryset
35         return self.model.objects.all()
36 
37 
38 class HDViewPointFilterSet(MapEntityFilterSet):
39 
40     class Meta(MapEntityFilterSet.Meta):
41         model = HDViewPoint
42         fields = ['title']
43
```

Path: `geotrek/maintenance/filters.py`
Content:
```
1 from django.db.models import Q
2 from django.conf import settings
3 from django.contrib.gis.geos import GeometryCollection
4 from django.utils.translation import gettext_lazy as _
5 from django_filters import ChoiceFilter, MultipleChoiceFilter, DateFromToRangeFilter, ModelMultipleChoiceFilter
6 
7 from mapentity.filters import PolygonFilter, PythonPolygonFilter
8 
9 from geotrek.altimetry.filters import AltimetryPointFilterSet
10 from geotrek.authent.filters import StructureRelatedFilterSet
11 from geotrek.common.filters import OptionalRangeFilter, RightFilter
12 from geotrek.common.widgets import OneLineRangeWidget
13 from geotrek.zoning.filters import (IntersectionFilterCity, IntersectionFilterDistrict,
14                                     IntersectionFilterRestrictedArea, IntersectionFilterRestrictedAreaType,
15                                     ZoningFilterSet)
16 from geotrek.zoning.models import City, District, RestrictedArea, RestrictedAreaType
17 
18 from .models import Intervention, Project, Contractor
19 
20 
21 class BboxInterventionFilterMixin:
22     def filter(self, qs, value):
23         if value:
24             value = value.transform(settings.SRID, clone=True)
25             return super().filter(qs, [value, ])
26         else:
27             return qs
28 
29 
30 class PolygonInterventionFilterMixin:
31     def get_geom(self, value):
32         return value
33 
34     def filter(self, qs, values):
35         if not values:
36             return qs
37         geom_intersect = GeometryCollection([self.get_geom(value) for value in values])
38         interventions = []
39         for element in qs:
40             if element.target:
41                 if not element.target.geom or element.target.geom.intersects(geom_intersect):
42                     interventions.append(element.pk)
43             elif element.target_type:
44                 interventions.append(element.pk)
45 
46         qs = qs.filter(pk__in=interventions).existing()
47         return qs
48 
49 
50 class PolygonProjectFilterMixin(PolygonInterventionFilterMixin):
51     def get_geom(self, value):
52         return value.geom
53 
54     def filter(self, qs, values):
55         if not values:
56             return qs
57         interventions = Intervention.objects.all()
58         return qs.filter(interventions__in=super().filter(interventions, values).values_list('id', flat=True))
59 
60 
61 class InterventionIntersectionFilterRestrictedAreaType(PolygonInterventionFilterMixin,
62                                                        IntersectionFilterRestrictedAreaType):
63 
64     def get_geom(self, value):
65         return value.geom
66 
67     def filter(self, qs, values):
68         restricted_areas = RestrictedArea.objects.filter(area_type__in=values)
69         if not restricted_areas and values:
70             return qs.none()
71         return super().filter(qs, list(restricted_areas))
72 
73 
74 class InterventionIntersectionFilterRestrictedArea(PolygonInterventionFilterMixin,
75                                                    IntersectionFilterRestrictedArea):
76     def get_geom(self, value):
77         return value.geom
78 
79 
80 class InterventionIntersectionFilterCity(PolygonInterventionFilterMixin,
81                                          IntersectionFilterCity):
82     def get_geom(self, value):
83         return value.geom
84 
85 
86 class InterventionIntersectionFilterDistrict(PolygonInterventionFilterMixin,
87                                              IntersectionFilterDistrict):
88     def get_geom(self, value):
89         return value.geom
90 
91 
92 class PolygonTopologyFilter(BboxInterventionFilterMixin, PolygonInterventionFilterMixin, PolygonFilter):
93     pass
94 
95 
96 class ProjectIntersectionFilterCity(PolygonProjectFilterMixin, RightFilter):
97     model = City
98 
99 
100 class ProjectIntersectionFilterDistrict(PolygonProjectFilterMixin, RightFilter):
101     model = District
102 
103 
104 class ProjectIntersectionFilterRestrictedArea(PolygonProjectFilterMixin, RightFilter):
105     model = RestrictedArea
106 
107 
108 class ProjectIntersectionFilterRestrictedAreaType(PolygonProjectFilterMixin, RightFilter):
109     model = RestrictedAreaType
110 
111     def filter(self, qs, values):
112         restricted_areas = RestrictedArea.objects.filter(area_type__in=values)
113         if not restricted_areas and values:
114             return qs.none()
115         return super().filter(qs, list(restricted_areas)).distinct()
116 
117 
118 class AltimetryInterventionFilterSet(AltimetryPointFilterSet):
119     length_3d = OptionalRangeFilter(field_name='length', label=_('length 3d'))
120     ascent = OptionalRangeFilter(label=_('ascent'))
121     descent = OptionalRangeFilter(label=_('descent'))
122     slope = OptionalRangeFilter(label=_('slope'))
123 
124 
125 class CustomDateFromToRangeFilter(DateFromToRangeFilter):
126     def __init__(self, *args, **kwargs):
127         super(DateFromToRangeFilter, self).__init__(*args, **kwargs)
128         self.field.fields[0].label = _('min %s') % self.field.label
129         self.field.fields[1].label = _('max %s') % self.field.label
130 
131 
132 class InterventionFilterSet(AltimetryInterventionFilterSet, ZoningFilterSet, StructureRelatedFilterSet):
133     ON_CHOICES = (('infrastructure', _("Infrastructure")), ('signage', _("Signage")), ('blade', _("Blade")),
134                   ('topology', _("Path")), ('trek', _("Trek")), ('poi', _("POI")), ('service', _("Service")),
135                   ('trail', _("Trail")))
136 
137     if 'geotrek.outdoor' in settings.INSTALLED_APPS:
138         ON_CHOICES += (('course', _("Outdoor Course")), ('site', _("Outdoor Site")),)
139 
140     bbox = PolygonTopologyFilter(lookup_expr='intersects')
141     begin_date = CustomDateFromToRangeFilter(widget=OneLineRangeWidget(attrs={'type': 'text', 'class': 'minmax-field', 'title': _('Filter by begin date range')},), label=_('begin date'))
142     end_date = CustomDateFromToRangeFilter(widget=OneLineRangeWidget(attrs={'type': 'text', 'class': 'minmax-field', 'title': _('Filter by end date range')},), label=_('end date'))
143     year = MultipleChoiceFilter(choices=lambda: Intervention.objects.year_choices(),
144                                 method='filter_year', label=_("Year"))
145     on = ChoiceFilter(field_name='target_type__model', choices=ON_CHOICES, label=_("On"), empty_label=_("On"))
146     area_type = InterventionIntersectionFilterRestrictedAreaType(label=_('Restricted area type'), required=False,
147                                                                  lookup_expr='intersects')
148     area = InterventionIntersectionFilterRestrictedArea(label=_('Restricted area'), required=False,
149                                                         lookup_expr='intersects')
150     city = InterventionIntersectionFilterCity(label=_('City'), required=False, lookup_expr='intersects')
151     district = InterventionIntersectionFilterDistrict(label=_('District'), required=False, lookup_expr='intersects')
152 
153     class Meta(StructureRelatedFilterSet.Meta):
154         model = Intervention
155         fields = StructureRelatedFilterSet.Meta.fields + [
156             'status', 'type', 'stake', 'subcontracting', 'project', 'contractors', 'on',
157         ]
158 
159     def filter_year(self, qs, name, values):
160         conditions = Q()
161         for value in values:
162             # Filter only with precise begin year
163             conditions |= Q(begin_date__year=value, end_date__isnull=True)
164             # Filter year between begin and end date
165             conditions |= Q(begin_date__year__lte=value, end_date__year__gte=value)
166         return qs.filter(conditions)
167 
168 
169 class ProjectFilterSet(StructureRelatedFilterSet):
170     bbox = PythonPolygonFilter(field_name='geom')
171     year = MultipleChoiceFilter(
172         label=_("Year of activity"), method='filter_year',
173         choices=lambda: Project.objects.year_choices()
174     )
175     city = ProjectIntersectionFilterCity(label=_('City'), lookup_expr='intersects', required=False)
176     district = ProjectIntersectionFilterDistrict(label=_('District'), lookup_expr='intersects', required=False)
177     area_type = ProjectIntersectionFilterRestrictedAreaType(label=_('Restricted area type'), lookup_expr='intersects', required=False)
178     area = ProjectIntersectionFilterRestrictedArea(label=_('Restricted area'), lookup_expr='intersects', required=False)
179     contractors = ModelMultipleChoiceFilter(label=_("Intervention contractors"), queryset=Contractor.objects.all(), method='filter_contractors')
180 
181     class Meta(StructureRelatedFilterSet.Meta):
182         model = Project
183         fields = StructureRelatedFilterSet.Meta.fields + [
184             'year', 'type', 'domain', 'contractors', 'project_owner',
185             'project_manager', 'founders'
186         ]
187 
188     def filter_contractors(self, qs, name, values):
189         q = Q()
190         if values:
191             q |= Q(contractors__in=values)
192             q |= Q(interventions__contractors__in=values)
193         return qs.filter(q)
194 
195     def filter_year(self, qs, name, values):
196         q = Q()
197         for value in values:
198             q |= Q(begin_year__lte=value, end_year__gte=value)
199         return qs.filter(q)
200 
201     def __init__(self, *args, **kwargs):
202         super().__init__(*args, **kwargs)
203         self.form.fields['year'].choices = Project.objects.year_choices()
204
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/geotrek/common/filters/__init__.py b/geotrek/common/filters/__init__.py
--- a/geotrek/common/filters/__init__.py
+++ b/geotrek/common/filters/__init__.py
@@ -1,3 +1,4 @@
+from django.utils.text import format_lazy
 from django.utils.translation import gettext_lazy as _
 from django_filters import ModelMultipleChoiceFilter, RangeFilter
 from mapentity.filters import MapEntityFilterSet
@@ -15,8 +16,8 @@
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        self.field.fields[0].label = _('min %s') % self.field.label
-        self.field.fields[1].label = _('max %s') % self.field.label
+        self.field.fields[0].label = format_lazy('{min} {label}', min=_('min'), label=self.field.label)
+        self.field.fields[1].label = format_lazy('{max} {label}', max=_('max'), label=self.field.label)
 
 
 class RightFilter(ModelMultipleChoiceFilter):
diff --git a/geotrek/maintenance/filters.py b/geotrek/maintenance/filters.py
--- a/geotrek/maintenance/filters.py
+++ b/geotrek/maintenance/filters.py
@@ -2,6 +2,7 @@
 from django.conf import settings
 from django.contrib.gis.geos import GeometryCollection
 from django.utils.translation import gettext_lazy as _
+from django.utils.text import format_lazy
 from django_filters import ChoiceFilter, MultipleChoiceFilter, DateFromToRangeFilter, ModelMultipleChoiceFilter
 
 from mapentity.filters import PolygonFilter, PythonPolygonFilter
@@ -125,8 +126,8 @@
 class CustomDateFromToRangeFilter(DateFromToRangeFilter):
     def __init__(self, *args, **kwargs):
         super(DateFromToRangeFilter, self).__init__(*args, **kwargs)
-        self.field.fields[0].label = _('min %s') % self.field.label
-        self.field.fields[1].label = _('max %s') % self.field.label
+        self.field.fields[0].label = format_lazy('{min} {label}', min=_('min'), label=self.field.label)
+        self.field.fields[1].label = format_lazy('{max} {label}', max=_('max'), label=self.field.label)
 
 
 class InterventionFilterSet(AltimetryInterventionFilterSet, ZoningFilterSet, StructureRelatedFilterSet):

{"golden_diff": "diff --git a/geotrek/common/filters/__init__.py b/geotrek/common/filters/__init__.py\n--- a/geotrek/common/filters/__init__.py\n+++ b/geotrek/common/filters/__init__.py\n@@ -1,3 +1,4 @@\n+from django.utils.text import format_lazy\n from django.utils.translation import gettext_lazy as _\n from django_filters import ModelMultipleChoiceFilter, RangeFilter\n from mapentity.filters import MapEntityFilterSet\n@@ -15,8 +16,8 @@\n \n     def __init__(self, *args, **kwargs):\n         super().__init__(*args, **kwargs)\n-        self.field.fields[0].label = _('min %s') % self.field.label\n-        self.field.fields[1].label = _('max %s') % self.field.label\n+        self.field.fields[0].label = format_lazy('{min} {label}', min=_('min'), label=self.field.label)\n+        self.field.fields[1].label = format_lazy('{max} {label}', max=_('max'), label=self.field.label)\n \n \n class RightFilter(ModelMultipleChoiceFilter):\ndiff --git a/geotrek/maintenance/filters.py b/geotrek/maintenance/filters.py\n--- a/geotrek/maintenance/filters.py\n+++ b/geotrek/maintenance/filters.py\n@@ -2,6 +2,7 @@\n from django.conf import settings\n from django.contrib.gis.geos import GeometryCollection\n from django.utils.translation import gettext_lazy as _\n+from django.utils.text import format_lazy\n from django_filters import ChoiceFilter, MultipleChoiceFilter, DateFromToRangeFilter, ModelMultipleChoiceFilter\n \n from mapentity.filters import PolygonFilter, PythonPolygonFilter\n@@ -125,8 +126,8 @@\n class CustomDateFromToRangeFilter(DateFromToRangeFilter):\n     def __init__(self, *args, **kwargs):\n         super(DateFromToRangeFilter, self).__init__(*args, **kwargs)\n-        self.field.fields[0].label = _('min %s') % self.field.label\n-        self.field.fields[1].label = _('max %s') % self.field.label\n+        self.field.fields[0].label = format_lazy('{min} {label}', min=_('min'), label=self.field.label)\n+        self.field.fields[1].label = format_lazy('{max} {label}', max=_('max'), label=self.field.label)\n \n \n class InterventionFilterSet(AltimetryInterventionFilterSet, ZoningFilterSet, StructureRelatedFilterSet):\n", "issue": "Traductions sur le \"hover\" des filtres\n# R\u00e9sum\u00e9\r\n\r\nDans l'interface, tout les filtres qui utilisent le widget `OneLineRangeWidget` ne sont pas traduit.\r\n\r\n# Reproduction\r\n\r\n- Pass\u00e9 geotrek admin en anglais\r\n- Remplir certains filtres (ceux avec min / max)\r\n- Fermer la fen\u00eatre des filtres\r\n- Placer la souris sur le bouton `Filter`\r\n\r\nOn pourra observer certains \u00e9l\u00e9ments traduits et d'autre non.\n", "before_files": [{"content": "from django.utils.translation import gettext_lazy as _\nfrom django_filters import ModelMultipleChoiceFilter, RangeFilter\nfrom mapentity.filters import MapEntityFilterSet\n\nfrom geotrek.common.filters.fields import ComaSeparatedMultipleModelChoiceField, OneLineRangeField\nfrom geotrek.common.models import HDViewPoint\n\n\nclass ComaSeparatedMultipleModelChoiceFilter(ModelMultipleChoiceFilter):\n    field_class = ComaSeparatedMultipleModelChoiceField\n\n\nclass OptionalRangeFilter(RangeFilter):\n    field_class = OneLineRangeField\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.field.fields[0].label = _('min %s') % self.field.label\n        self.field.fields[1].label = _('max %s') % self.field.label\n\n\nclass RightFilter(ModelMultipleChoiceFilter):\n    model = None\n    queryset = None\n\n    def __init__(self, *args, **kwargs):\n        kwargs.setdefault('queryset', self.get_queryset())\n        super().__init__(*args, **kwargs)\n        self.field.widget.attrs['class'] = self.field.widget.attrs.get('class', '') + 'right-filter'\n        self.field.widget.renderer = None\n\n    def get_queryset(self, request=None):\n        if self.queryset is not None:\n            return self.queryset\n        return self.model.objects.all()\n\n\nclass HDViewPointFilterSet(MapEntityFilterSet):\n\n    class Meta(MapEntityFilterSet.Meta):\n        model = HDViewPoint\n        fields = ['title']\n", "path": "geotrek/common/filters/__init__.py"}, {"content": "from django.db.models import Q\nfrom django.conf import settings\nfrom django.contrib.gis.geos import GeometryCollection\nfrom django.utils.translation import gettext_lazy as _\nfrom django_filters import ChoiceFilter, MultipleChoiceFilter, DateFromToRangeFilter, ModelMultipleChoiceFilter\n\nfrom mapentity.filters import PolygonFilter, PythonPolygonFilter\n\nfrom geotrek.altimetry.filters import AltimetryPointFilterSet\nfrom geotrek.authent.filters import StructureRelatedFilterSet\nfrom geotrek.common.filters import OptionalRangeFilter, RightFilter\nfrom geotrek.common.widgets import OneLineRangeWidget\nfrom geotrek.zoning.filters import (IntersectionFilterCity, IntersectionFilterDistrict,\n                                    IntersectionFilterRestrictedArea, IntersectionFilterRestrictedAreaType,\n                                    ZoningFilterSet)\nfrom geotrek.zoning.models import City, District, RestrictedArea, RestrictedAreaType\n\nfrom .models import Intervention, Project, Contractor\n\n\nclass BboxInterventionFilterMixin:\n    def filter(self, qs, value):\n        if value:\n            value = value.transform(settings.SRID, clone=True)\n            return super().filter(qs, [value, ])\n        else:\n            return qs\n\n\nclass PolygonInterventionFilterMixin:\n    def get_geom(self, value):\n        return value\n\n    def filter(self, qs, values):\n        if not values:\n            return qs\n        geom_intersect = GeometryCollection([self.get_geom(value) for value in values])\n        interventions = []\n        for element in qs:\n            if element.target:\n                if not element.target.geom or element.target.geom.intersects(geom_intersect):\n                    interventions.append(element.pk)\n            elif element.target_type:\n                interventions.append(element.pk)\n\n        qs = qs.filter(pk__in=interventions).existing()\n        return qs\n\n\nclass PolygonProjectFilterMixin(PolygonInterventionFilterMixin):\n    def get_geom(self, value):\n        return value.geom\n\n    def filter(self, qs, values):\n        if not values:\n            return qs\n        interventions = Intervention.objects.all()\n        return qs.filter(interventions__in=super().filter(interventions, values).values_list('id', flat=True))\n\n\nclass InterventionIntersectionFilterRestrictedAreaType(PolygonInterventionFilterMixin,\n                                                       IntersectionFilterRestrictedAreaType):\n\n    def get_geom(self, value):\n        return value.geom\n\n    def filter(self, qs, values):\n        restricted_areas = RestrictedArea.objects.filter(area_type__in=values)\n        if not restricted_areas and values:\n            return qs.none()\n        return super().filter(qs, list(restricted_areas))\n\n\nclass InterventionIntersectionFilterRestrictedArea(PolygonInterventionFilterMixin,\n                                                   IntersectionFilterRestrictedArea):\n    def get_geom(self, value):\n        return value.geom\n\n\nclass InterventionIntersectionFilterCity(PolygonInterventionFilterMixin,\n                                         IntersectionFilterCity):\n    def get_geom(self, value):\n        return value.geom\n\n\nclass InterventionIntersectionFilterDistrict(PolygonInterventionFilterMixin,\n                                             IntersectionFilterDistrict):\n    def get_geom(self, value):\n        return value.geom\n\n\nclass PolygonTopologyFilter(BboxInterventionFilterMixin, PolygonInterventionFilterMixin, PolygonFilter):\n    pass\n\n\nclass ProjectIntersectionFilterCity(PolygonProjectFilterMixin, RightFilter):\n    model = City\n\n\nclass ProjectIntersectionFilterDistrict(PolygonProjectFilterMixin, RightFilter):\n    model = District\n\n\nclass ProjectIntersectionFilterRestrictedArea(PolygonProjectFilterMixin, RightFilter):\n    model = RestrictedArea\n\n\nclass ProjectIntersectionFilterRestrictedAreaType(PolygonProjectFilterMixin, RightFilter):\n    model = RestrictedAreaType\n\n    def filter(self, qs, values):\n        restricted_areas = RestrictedArea.objects.filter(area_type__in=values)\n        if not restricted_areas and values:\n            return qs.none()\n        return super().filter(qs, list(restricted_areas)).distinct()\n\n\nclass AltimetryInterventionFilterSet(AltimetryPointFilterSet):\n    length_3d = OptionalRangeFilter(field_name='length', label=_('length 3d'))\n    ascent = OptionalRangeFilter(label=_('ascent'))\n    descent = OptionalRangeFilter(label=_('descent'))\n    slope = OptionalRangeFilter(label=_('slope'))\n\n\nclass CustomDateFromToRangeFilter(DateFromToRangeFilter):\n    def __init__(self, *args, **kwargs):\n        super(DateFromToRangeFilter, self).__init__(*args, **kwargs)\n        self.field.fields[0].label = _('min %s') % self.field.label\n        self.field.fields[1].label = _('max %s') % self.field.label\n\n\nclass InterventionFilterSet(AltimetryInterventionFilterSet, ZoningFilterSet, StructureRelatedFilterSet):\n    ON_CHOICES = (('infrastructure', _(\"Infrastructure\")), ('signage', _(\"Signage\")), ('blade', _(\"Blade\")),\n                  ('topology', _(\"Path\")), ('trek', _(\"Trek\")), ('poi', _(\"POI\")), ('service', _(\"Service\")),\n                  ('trail', _(\"Trail\")))\n\n    if 'geotrek.outdoor' in settings.INSTALLED_APPS:\n        ON_CHOICES += (('course', _(\"Outdoor Course\")), ('site', _(\"Outdoor Site\")),)\n\n    bbox = PolygonTopologyFilter(lookup_expr='intersects')\n    begin_date = CustomDateFromToRangeFilter(widget=OneLineRangeWidget(attrs={'type': 'text', 'class': 'minmax-field', 'title': _('Filter by begin date range')},), label=_('begin date'))\n    end_date = CustomDateFromToRangeFilter(widget=OneLineRangeWidget(attrs={'type': 'text', 'class': 'minmax-field', 'title': _('Filter by end date range')},), label=_('end date'))\n    year = MultipleChoiceFilter(choices=lambda: Intervention.objects.year_choices(),\n                                method='filter_year', label=_(\"Year\"))\n    on = ChoiceFilter(field_name='target_type__model', choices=ON_CHOICES, label=_(\"On\"), empty_label=_(\"On\"))\n    area_type = InterventionIntersectionFilterRestrictedAreaType(label=_('Restricted area type'), required=False,\n                                                                 lookup_expr='intersects')\n    area = InterventionIntersectionFilterRestrictedArea(label=_('Restricted area'), required=False,\n                                                        lookup_expr='intersects')\n    city = InterventionIntersectionFilterCity(label=_('City'), required=False, lookup_expr='intersects')\n    district = InterventionIntersectionFilterDistrict(label=_('District'), required=False, lookup_expr='intersects')\n\n    class Meta(StructureRelatedFilterSet.Meta):\n        model = Intervention\n        fields = StructureRelatedFilterSet.Meta.fields + [\n            'status', 'type', 'stake', 'subcontracting', 'project', 'contractors', 'on',\n        ]\n\n    def filter_year(self, qs, name, values):\n        conditions = Q()\n        for value in values:\n            # Filter only with precise begin year\n            conditions |= Q(begin_date__year=value, end_date__isnull=True)\n            # Filter year between begin and end date\n            conditions |= Q(begin_date__year__lte=value, end_date__year__gte=value)\n        return qs.filter(conditions)\n\n\nclass ProjectFilterSet(StructureRelatedFilterSet):\n    bbox = PythonPolygonFilter(field_name='geom')\n    year = MultipleChoiceFilter(\n        label=_(\"Year of activity\"), method='filter_year',\n        choices=lambda: Project.objects.year_choices()\n    )\n    city = ProjectIntersectionFilterCity(label=_('City'), lookup_expr='intersects', required=False)\n    district = ProjectIntersectionFilterDistrict(label=_('District'), lookup_expr='intersects', required=False)\n    area_type = ProjectIntersectionFilterRestrictedAreaType(label=_('Restricted area type'), lookup_expr='intersects', required=False)\n    area = ProjectIntersectionFilterRestrictedArea(label=_('Restricted area'), lookup_expr='intersects', required=False)\n    contractors = ModelMultipleChoiceFilter(label=_(\"Intervention contractors\"), queryset=Contractor.objects.all(), method='filter_contractors')\n\n    class Meta(StructureRelatedFilterSet.Meta):\n        model = Project\n        fields = StructureRelatedFilterSet.Meta.fields + [\n            'year', 'type', 'domain', 'contractors', 'project_owner',\n            'project_manager', 'founders'\n        ]\n\n    def filter_contractors(self, qs, name, values):\n        q = Q()\n        if values:\n            q |= Q(contractors__in=values)\n            q |= Q(interventions__contractors__in=values)\n        return qs.filter(q)\n\n    def filter_year(self, qs, name, values):\n        q = Q()\n        for value in values:\n            q |= Q(begin_year__lte=value, end_year__gte=value)\n        return qs.filter(q)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.form.fields['year'].choices = Project.objects.year_choices()\n", "path": "geotrek/maintenance/filters.py"}], "after_files": [{"content": "from django.utils.text import format_lazy\nfrom django.utils.translation import gettext_lazy as _\nfrom django_filters import ModelMultipleChoiceFilter, RangeFilter\nfrom mapentity.filters import MapEntityFilterSet\n\nfrom geotrek.common.filters.fields import ComaSeparatedMultipleModelChoiceField, OneLineRangeField\nfrom geotrek.common.models import HDViewPoint\n\n\nclass ComaSeparatedMultipleModelChoiceFilter(ModelMultipleChoiceFilter):\n    field_class = ComaSeparatedMultipleModelChoiceField\n\n\nclass OptionalRangeFilter(RangeFilter):\n    field_class = OneLineRangeField\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.field.fields[0].label = format_lazy('{min} {label}', min=_('min'), label=self.field.label)\n        self.field.fields[1].label = format_lazy('{max} {label}', max=_('max'), label=self.field.label)\n\n\nclass RightFilter(ModelMultipleChoiceFilter):\n    model = None\n    queryset = None\n\n    def __init__(self, *args, **kwargs):\n        kwargs.setdefault('queryset', self.get_queryset())\n        super().__init__(*args, **kwargs)\n        self.field.widget.attrs['class'] = self.field.widget.attrs.get('class', '') + 'right-filter'\n        self.field.widget.renderer = None\n\n    def get_queryset(self, request=None):\n        if self.queryset is not None:\n            return self.queryset\n        return self.model.objects.all()\n\n\nclass HDViewPointFilterSet(MapEntityFilterSet):\n\n    class Meta(MapEntityFilterSet.Meta):\n        model = HDViewPoint\n        fields = ['title']\n", "path": "geotrek/common/filters/__init__.py"}, {"content": "from django.db.models import Q\nfrom django.conf import settings\nfrom django.contrib.gis.geos import GeometryCollection\nfrom django.utils.translation import gettext_lazy as _\nfrom django.utils.text import format_lazy\nfrom django_filters import ChoiceFilter, MultipleChoiceFilter, DateFromToRangeFilter, ModelMultipleChoiceFilter\n\nfrom mapentity.filters import PolygonFilter, PythonPolygonFilter\n\nfrom geotrek.altimetry.filters import AltimetryPointFilterSet\nfrom geotrek.authent.filters import StructureRelatedFilterSet\nfrom geotrek.common.filters import OptionalRangeFilter, RightFilter\nfrom geotrek.common.widgets import OneLineRangeWidget\nfrom geotrek.zoning.filters import (IntersectionFilterCity, IntersectionFilterDistrict,\n                                    IntersectionFilterRestrictedArea, IntersectionFilterRestrictedAreaType,\n                                    ZoningFilterSet)\nfrom geotrek.zoning.models import City, District, RestrictedArea, RestrictedAreaType\n\nfrom .models import Intervention, Project, Contractor\n\n\nclass BboxInterventionFilterMixin:\n    def filter(self, qs, value):\n        if value:\n            value = value.transform(settings.SRID, clone=True)\n            return super().filter(qs, [value, ])\n        else:\n            return qs\n\n\nclass PolygonInterventionFilterMixin:\n    def get_geom(self, value):\n        return value\n\n    def filter(self, qs, values):\n        if not values:\n            return qs\n        geom_intersect = GeometryCollection([self.get_geom(value) for value in values])\n        interventions = []\n        for element in qs:\n            if element.target:\n                if not element.target.geom or element.target.geom.intersects(geom_intersect):\n                    interventions.append(element.pk)\n            elif element.target_type:\n                interventions.append(element.pk)\n\n        qs = qs.filter(pk__in=interventions).existing()\n        return qs\n\n\nclass PolygonProjectFilterMixin(PolygonInterventionFilterMixin):\n    def get_geom(self, value):\n        return value.geom\n\n    def filter(self, qs, values):\n        if not values:\n            return qs\n        interventions = Intervention.objects.all()\n        return qs.filter(interventions__in=super().filter(interventions, values).values_list('id', flat=True))\n\n\nclass InterventionIntersectionFilterRestrictedAreaType(PolygonInterventionFilterMixin,\n                                                       IntersectionFilterRestrictedAreaType):\n\n    def get_geom(self, value):\n        return value.geom\n\n    def filter(self, qs, values):\n        restricted_areas = RestrictedArea.objects.filter(area_type__in=values)\n        if not restricted_areas and values:\n            return qs.none()\n        return super().filter(qs, list(restricted_areas))\n\n\nclass InterventionIntersectionFilterRestrictedArea(PolygonInterventionFilterMixin,\n                                                   IntersectionFilterRestrictedArea):\n    def get_geom(self, value):\n        return value.geom\n\n\nclass InterventionIntersectionFilterCity(PolygonInterventionFilterMixin,\n                                         IntersectionFilterCity):\n    def get_geom(self, value):\n        return value.geom\n\n\nclass InterventionIntersectionFilterDistrict(PolygonInterventionFilterMixin,\n                                             IntersectionFilterDistrict):\n    def get_geom(self, value):\n        return value.geom\n\n\nclass PolygonTopologyFilter(BboxInterventionFilterMixin, PolygonInterventionFilterMixin, PolygonFilter):\n    pass\n\n\nclass ProjectIntersectionFilterCity(PolygonProjectFilterMixin, RightFilter):\n    model = City\n\n\nclass ProjectIntersectionFilterDistrict(PolygonProjectFilterMixin, RightFilter):\n    model = District\n\n\nclass ProjectIntersectionFilterRestrictedArea(PolygonProjectFilterMixin, RightFilter):\n    model = RestrictedArea\n\n\nclass ProjectIntersectionFilterRestrictedAreaType(PolygonProjectFilterMixin, RightFilter):\n    model = RestrictedAreaType\n\n    def filter(self, qs, values):\n        restricted_areas = RestrictedArea.objects.filter(area_type__in=values)\n        if not restricted_areas and values:\n            return qs.none()\n        return super().filter(qs, list(restricted_areas)).distinct()\n\n\nclass AltimetryInterventionFilterSet(AltimetryPointFilterSet):\n    length_3d = OptionalRangeFilter(field_name='length', label=_('length 3d'))\n    ascent = OptionalRangeFilter(label=_('ascent'))\n    descent = OptionalRangeFilter(label=_('descent'))\n    slope = OptionalRangeFilter(label=_('slope'))\n\n\nclass CustomDateFromToRangeFilter(DateFromToRangeFilter):\n    def __init__(self, *args, **kwargs):\n        super(DateFromToRangeFilter, self).__init__(*args, **kwargs)\n        self.field.fields[0].label = format_lazy('{min} {label}', min=_('min'), label=self.field.label)\n        self.field.fields[1].label = format_lazy('{max} {label}', max=_('max'), label=self.field.label)\n\n\nclass InterventionFilterSet(AltimetryInterventionFilterSet, ZoningFilterSet, StructureRelatedFilterSet):\n    ON_CHOICES = (('infrastructure', _(\"Infrastructure\")), ('signage', _(\"Signage\")), ('blade', _(\"Blade\")),\n                  ('topology', _(\"Path\")), ('trek', _(\"Trek\")), ('poi', _(\"POI\")), ('service', _(\"Service\")),\n                  ('trail', _(\"Trail\")))\n\n    if 'geotrek.outdoor' in settings.INSTALLED_APPS:\n        ON_CHOICES += (('course', _(\"Outdoor Course\")), ('site', _(\"Outdoor Site\")),)\n\n    bbox = PolygonTopologyFilter(lookup_expr='intersects')\n    begin_date = CustomDateFromToRangeFilter(widget=OneLineRangeWidget(attrs={'type': 'text', 'class': 'minmax-field', 'title': _('Filter by begin date range')},), label=_('begin date'))\n    end_date = CustomDateFromToRangeFilter(widget=OneLineRangeWidget(attrs={'type': 'text', 'class': 'minmax-field', 'title': _('Filter by end date range')},), label=_('end date'))\n    year = MultipleChoiceFilter(choices=lambda: Intervention.objects.year_choices(),\n                                method='filter_year', label=_(\"Year\"))\n    on = ChoiceFilter(field_name='target_type__model', choices=ON_CHOICES, label=_(\"On\"), empty_label=_(\"On\"))\n    area_type = InterventionIntersectionFilterRestrictedAreaType(label=_('Restricted area type'), required=False,\n                                                                 lookup_expr='intersects')\n    area = InterventionIntersectionFilterRestrictedArea(label=_('Restricted area'), required=False,\n                                                        lookup_expr='intersects')\n    city = InterventionIntersectionFilterCity(label=_('City'), required=False, lookup_expr='intersects')\n    district = InterventionIntersectionFilterDistrict(label=_('District'), required=False, lookup_expr='intersects')\n\n    class Meta(StructureRelatedFilterSet.Meta):\n        model = Intervention\n        fields = StructureRelatedFilterSet.Meta.fields + [\n            'status', 'type', 'stake', 'subcontracting', 'project', 'contractors', 'on',\n        ]\n\n    def filter_year(self, qs, name, values):\n        conditions = Q()\n        for value in values:\n            # Filter only with precise begin year\n            conditions |= Q(begin_date__year=value, end_date__isnull=True)\n            # Filter year between begin and end date\n            conditions |= Q(begin_date__year__lte=value, end_date__year__gte=value)\n        return qs.filter(conditions)\n\n\nclass ProjectFilterSet(StructureRelatedFilterSet):\n    bbox = PythonPolygonFilter(field_name='geom')\n    year = MultipleChoiceFilter(\n        label=_(\"Year of activity\"), method='filter_year',\n        choices=lambda: Project.objects.year_choices()\n    )\n    city = ProjectIntersectionFilterCity(label=_('City'), lookup_expr='intersects', required=False)\n    district = ProjectIntersectionFilterDistrict(label=_('District'), lookup_expr='intersects', required=False)\n    area_type = ProjectIntersectionFilterRestrictedAreaType(label=_('Restricted area type'), lookup_expr='intersects', required=False)\n    area = ProjectIntersectionFilterRestrictedArea(label=_('Restricted area'), lookup_expr='intersects', required=False)\n    contractors = ModelMultipleChoiceFilter(label=_(\"Intervention contractors\"), queryset=Contractor.objects.all(), method='filter_contractors')\n\n    class Meta(StructureRelatedFilterSet.Meta):\n        model = Project\n        fields = StructureRelatedFilterSet.Meta.fields + [\n            'year', 'type', 'domain', 'contractors', 'project_owner',\n            'project_manager', 'founders'\n        ]\n\n    def filter_contractors(self, qs, name, values):\n        q = Q()\n        if values:\n            q |= Q(contractors__in=values)\n            q |= Q(interventions__contractors__in=values)\n        return qs.filter(q)\n\n    def filter_year(self, qs, name, values):\n        q = Q()\n        for value in values:\n            q |= Q(begin_year__lte=value, end_year__gte=value)\n        return qs.filter(q)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.form.fields['year'].choices = Project.objects.year_choices()\n", "path": "geotrek/maintenance/filters.py"}]}