Skip to content

Commit

Permalink
refactor(Périmètres): Bouger le filtre autocomplete de l'API vers le …
Browse files Browse the repository at this point in the history
…modèle (#1264)
  • Loading branch information
raphodn authored Jun 13, 2024
1 parent 72c604b commit 8d5c5e7
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 24 deletions.
25 changes: 1 addition & 24 deletions lemarche/api/perimeters/filters.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import django_filters
from django.conf import settings
from django.contrib.postgres.search import TrigramSimilarity
from django.db.models import Q

from lemarche.perimeters.models import Perimeter

Expand Down Expand Up @@ -30,28 +28,7 @@ class Meta:
fields = ["q", "results"]

def name_or_post_code_autocomplete_search(self, queryset, name, value):
if not value:
return queryset
# department code or city post_code
if value.isnumeric():
# city post_code
if len(value) == 5:
queryset = queryset.filter(post_codes__contains=[value])
# if we wanted to allow search on insee_code as well
# return queryset.filter(Q(insee_code=value) | Q(post_codes__contains=[value]))
# department code or beginning of city post_code
elif len(value) == 2:
queryset = queryset.filter(Q(insee_code=value) | Q(post_codes__0__startswith=value))
# city post_code
else:
queryset = queryset.filter(post_codes__0__startswith=value)
return queryset.order_by("insee_code")
# normal name filtering
return (
queryset.annotate(similarity=TrigramSimilarity("name", value))
.filter(similarity__gt=0.1)
.order_by("-similarity")
)
return queryset.name_or_post_code_autocomplete_search(value)

def max_number_of_results(self, queryset, name, value):
if not value:
Expand Down
30 changes: 30 additions & 0 deletions lemarche/perimeters/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

from django.contrib.gis.db import models as gis_models
from django.contrib.postgres.indexes import GinIndex
from django.contrib.postgres.search import TrigramSimilarity
from django.db import models
from django.db.models import Q
from django.template.defaultfilters import slugify
from django.utils import timezone

Expand All @@ -18,6 +20,34 @@ def cities(self):
def regions(self):
return self.filter(kind="REGION")

def name_search(self, value):
return (
self.annotate(similarity=TrigramSimilarity("name", value))
.filter(similarity__gt=0.1)
.order_by("-similarity")
)

def post_code_search(self, value):
# city post_code
if len(value) == 5:
qs = self.filter(post_codes__contains=[value])
# if we wanted to allow search on insee_code as well
# return queryset.filter(Q(insee_code=value) | Q(post_codes__contains=[value]))
# department code or beginning of city post_code
elif len(value) == 2:
qs = self.filter(Q(insee_code=value) | Q(post_codes__0__startswith=value))
# city post_code
else:
qs = self.filter(post_codes__0__startswith=value)
return qs.order_by("insee_code")

def name_or_post_code_autocomplete_search(self, value):
if not value:
return self
if value.isnumeric():
return self.post_code_search(value)
return self.name_search(value)


class Perimeter(models.Model):
KIND_CITY = "CITY"
Expand Down
50 changes: 50 additions & 0 deletions lemarche/perimeters/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,53 @@ def test_name_display_property(self):
self.assertEqual(str(self.perimeter_city), "Grenoble (38)")
self.assertEqual(str(self.perimeter_department), "Isère")
self.assertEqual(str(self.perimeter_region), "Auvergne-Rhône-Alpes")


class PerimeterQuerysetTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.perimeter_city = PerimeterFactory(
name="Grenoble",
kind=Perimeter.KIND_CITY,
insee_code="38185",
department_code="38",
region_code="84",
post_codes=["38000", "38100", "38700"],
# coords=Point(5.7301, 45.1825),
)
cls.perimeter_department = PerimeterFactory(
name="Isère", kind=Perimeter.KIND_DEPARTMENT, insee_code="38", region_code="84"
)
cls.perimeter_department_2 = PerimeterFactory(
name="Guadeloupe", kind=Perimeter.KIND_DEPARTMENT, insee_code="971", region_code="01"
)
cls.perimeter_region = PerimeterFactory(
name="Auvergne-Rhône-Alpes", kind=Perimeter.KIND_REGION, insee_code="R84"
)
cls.perimeter_region_2 = PerimeterFactory(name="Guadeloupe", kind=Perimeter.KIND_REGION, insee_code="R01")

def test_cities(self):
self.assertEqual(Perimeter.objects.count(), 5)
qs = Perimeter.objects.cities()
self.assertEqual(qs.count(), 1)
self.assertEqual(qs.first(), self.perimeter_city)

def test_regions(self):
self.assertEqual(Perimeter.objects.count(), 5)
qs = Perimeter.objects.regions()
self.assertEqual(qs.count(), 2)
self.assertEqual(qs.first(), self.perimeter_region)

def test_name_search(self):
qs = Perimeter.objects.name_search("Grenoble")
self.assertEqual(qs.count(), 1)
self.assertEqual(qs.first(), self.perimeter_city)
qs = Perimeter.objects.name_search("guadelou")
self.assertEqual(qs.count(), 2)

def test_post_code_search(self):
qs = Perimeter.objects.post_code_search("38000")
self.assertEqual(qs.count(), 1)
self.assertEqual(qs.first(), self.perimeter_city)
qs = Perimeter.objects.post_code_search("38")
self.assertEqual(qs.count(), 2)

0 comments on commit 8d5c5e7

Please sign in to comment.