summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2023-04-18 17:21:38 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2023-04-18 17:21:38 +0200
commita589b3ef96c9adf4e408713201ffe7d269e4f78f (patch)
tree5ad635c7fba5f5d1d1a40a5c5066321c870edfac
parent2b9862d29073e31cc89e807fd355a691b0d932dd (diff)
downloadIshtar-a589b3ef96c9adf4e408713201ffe7d269e4f78f.tar.bz2
Ishtar-a589b3ef96c9adf4e408713201ffe7d269e4f78f.zip
Document -> Town/Area: models, admin, forms
-rw-r--r--ishtar_common/admin.py17
-rw-r--r--ishtar_common/forms_common.py3
-rw-r--r--ishtar_common/migrations/0228_auto_20230418_1622.py53
-rw-r--r--ishtar_common/models.py47
-rw-r--r--ishtar_common/models_common.py359
-rw-r--r--ishtar_common/tests.py32
-rw-r--r--ishtar_common/urls.py1
-rw-r--r--ishtar_common/views.py17
8 files changed, 351 insertions, 178 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py
index c824b36f5..e4c4e90ed 100644
--- a/ishtar_common/admin.py
+++ b/ishtar_common/admin.py
@@ -671,7 +671,8 @@ class PersonAdmin(HistorizedObjectAdmin):
"merge_exclusion",
"merge_candidate",
)
- autocomplete_fields = ["attached_to"]
+ autocomplete_fields = ["attached_to", "lock_user", "precise_town"]
+ readonly_fields = HistorizedObjectAdmin.readonly_fields + ["cached_label"]
model = models.Person
inlines = [ProfileInline]
@@ -1151,7 +1152,7 @@ class TownAdmin(ImportGEOJSONActionAdmin, ImportActionAdmin):
search_fields += ["numero_insee"]
list_filter = ("areas",)
form = AdminTownForm
- autocomplete_fields = ["children", "main_geodata", "geodata"]
+ autocomplete_fields = ["children", "main_geodata", "geodata", "documents", "main_image"]
inlines = [TownParentInline]
actions = [
export_as_csv_action(exclude=["center", "limit"]),
@@ -1429,6 +1430,16 @@ class DocumentTag(MergeActionAdmin, GeneralTypeAdmin):
class DocumentAdmin(admin.ModelAdmin):
model = models.Document
search_fields = ("title", "reference", "internal_reference")
+ autocomplete_fields = ("lock_user", "source", "authors")
+ readonly_fields = [
+ "history_creator",
+ "history_modifier",
+ "search_vector",
+ "history_m2m",
+ "imports",
+ "cached_label",
+ "cache_related_label"
+ ]
admin_site.register(models.Document, DocumentAdmin)
@@ -1439,7 +1450,7 @@ class AreaAdmin(CreateDepartmentActionAdmin):
search_fields = ("label", "reference")
list_filter = ("parent",)
model = models.Area
- autocomplete_fields = ["towns", "parent"]
+ autocomplete_fields = ["towns", "parent", "documents", "main_image"]
admin_site.register(models.Area, AreaAdmin)
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index f031b280f..76e5bbf1e 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -2210,6 +2210,8 @@ class DocumentSelect(HistorySelect):
),
validators=[models.valid_id(Container)],
)
+ town = get_town_field()
+ area = widgets.Select2SimpleField(label=_("Area"))
receipt_date__before = forms.DateField(
label=_("Receipt date before"), widget=DatePicker
)
@@ -2237,6 +2239,7 @@ class DocumentSelect(HistorySelect):
FieldType("language", models.Language),
FieldType("licenses", models.LicenseType),
FieldType("operations__operation_type", models.OperationType),
+ FieldType("area", models.Area),
]
PROFILE_FILTER = {
diff --git a/ishtar_common/migrations/0228_auto_20230418_1622.py b/ishtar_common/migrations/0228_auto_20230418_1622.py
new file mode 100644
index 000000000..65154f308
--- /dev/null
+++ b/ishtar_common/migrations/0228_auto_20230418_1622.py
@@ -0,0 +1,53 @@
+# Generated by Django 2.2.24 on 2023-04-18 16:22
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0227_auto_20230406_1834'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='area',
+ options={'ordering': ('label',), 'verbose_name': 'Area', 'verbose_name_plural': 'Areas'},
+ ),
+ migrations.AddField(
+ model_name='area',
+ name='documents',
+ field=models.ManyToManyField(blank=True, related_name='areas', to='ishtar_common.Document', verbose_name='Documents'),
+ ),
+ migrations.AddField(
+ model_name='area',
+ name='main_image',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='main_image_areas', to='ishtar_common.Document', verbose_name='Main image'),
+ ),
+ migrations.AddField(
+ model_name='town',
+ name='documents',
+ field=models.ManyToManyField(blank=True, related_name='towns', to='ishtar_common.Document', verbose_name='Documents'),
+ ),
+ migrations.AddField(
+ model_name='town',
+ name='main_image',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='main_image_towns', to='ishtar_common.Document', verbose_name='Main image'),
+ ),
+ migrations.AlterField(
+ model_name='document',
+ name='authors',
+ field=models.ManyToManyField(blank=True, related_name='documents', to='ishtar_common.Author', verbose_name='Authors'),
+ ),
+ migrations.AlterField(
+ model_name='document',
+ name='container_ref_id',
+ field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Container reference ID'),
+ ),
+ migrations.AlterField(
+ model_name='historicaldocument',
+ name='container_ref_id',
+ field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Container reference ID'),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index ba317998f..dd968f891 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -2341,7 +2341,8 @@ class DocumentTemplate(models.Model):
return output_name
-class Area(HierarchicalType):
+class Area(HierarchicalType, DocumentItem):
+ SLUG = "area"
towns = models.ManyToManyField(
Town, verbose_name=_("Towns"), blank=True, related_name="areas"
)
@@ -2355,10 +2356,21 @@ class Area(HierarchicalType):
related_name="children",
on_delete=models.SET_NULL,
)
+ documents = models.ManyToManyField(
+ "Document", related_name="areas", verbose_name=_("Documents"), blank=True
+ )
+ main_image = models.ForeignKey(
+ "Document",
+ related_name="main_image_areas",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Main image"),
+ blank=True,
+ null=True,
+ )
class Meta:
- verbose_name = _("Town - Area")
- verbose_name_plural = _("Town - Areas")
+ verbose_name = _("Area")
+ verbose_name_plural = _("Areas")
ordering = ("label",)
ADMIN_SECTION = _("Geography")
@@ -2435,6 +2447,12 @@ class Area(HierarchicalType):
label.append(self.parent.full_label)
return " / ".join(label)
+ def _get_base_image_path(self):
+ return self.SLUG
+
+
+#m2m_changed.connect(document_attached_changed, sender=Area.documents.through)
+
GENDER = (
("M", _("Male")),
@@ -3844,6 +3862,8 @@ class Document(
"containers",
"files",
"administrativeacts",
+ "towns",
+ "areas",
]
# same fields but in order for forms
RELATED_MODELS_ALT = [
@@ -3857,6 +3877,8 @@ class Document(
"containers",
"treatments",
"treatment_files",
+ "towns",
+ "areas",
]
SLUG = "document"
LINK_SPLIT = "<||>"
@@ -3874,6 +3896,10 @@ class Document(
"history_creator_id",
"containers",
"sites",
+ "towns",
+ "areas",
+ "main_image_towns",
+ "main_image_areas",
"main_image_warehouses",
"main_image_operations",
"main_image_treatments",
@@ -3915,6 +3941,8 @@ class Document(
SearchVectorConfig("warehouses__name"),
SearchVectorConfig("containers__cached_label"),
SearchVectorConfig("files__cached_label"),
+ SearchVectorConfig("towns__name"),
+ SearchVectorConfig("areas__label"),
]
PARENT_SEARCH_VECTORS = [
"authors",
@@ -4082,6 +4110,14 @@ class Document(
pgettext_lazy("key for text search", "warehouse"),
"warehouses__name__iexact",
),
+ "town": SearchAltName(
+ pgettext_lazy("key for text search", "town"),
+ "towns__name__iexact",
+ ),
+ "area": SearchAltName(
+ pgettext_lazy("key for text search", "area"),
+ "areas__label__iexact",
+ ),
"image__isnull": SearchAltName(
pgettext_lazy("key for text search", "has-image"), "image__isnull"
),
@@ -4275,7 +4311,8 @@ class Document(
)
scale = models.CharField(_("Scale"), max_length=30, null=True, blank=True)
authors = models.ManyToManyField(
- Author, verbose_name=_("Authors"), related_name="documents"
+ Author, verbose_name=_("Authors"), related_name="documents",
+ blank=True
)
authors_raw = models.CharField(
verbose_name=_("Authors (raw)"), blank=True, null=True, max_length=250
@@ -4302,7 +4339,7 @@ class Document(
)
# container = models.ForeignKey("archaeological_warehouse.Container")
container_ref_id = models.PositiveIntegerField(
- verbose_name=_("Container ID"), blank=True, null=True
+ verbose_name=_("Container reference ID"), blank=True, null=True
)
# container_ref = models.ForeignKey("archaeological_warehouse.Container")
comment = models.TextField(_("Comment"), blank=True, default="")
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index 1e6da2b7d..8942d57c2 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -1978,6 +1978,175 @@ class OwnPerms(object):
return q
+class DocumentItem:
+ ALT_NAMES = {
+ "documents__image__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-image"),
+ "documents__image__isnull",
+ ),
+ "documents__associated_url__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-url"),
+ "documents__associated_url__isnull",
+ ),
+ "documents__associated_file__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-attached-file"),
+ "documents__associated_file__isnull",
+ ),
+ }
+
+ def documents_list(self) -> list:
+ Document = apps.get_model("ishtar_common", "Document")
+ return self.get_associated_main_item_list("documents", Document)
+
+ def public_representation(self):
+ images = []
+ if getattr(self, "main_image", None):
+ images.append(self.main_image.public_representation())
+ images += [
+ image.public_representation()
+ for image in self.images_without_main_image.all()
+ ]
+ return {"images": images}
+
+ @property
+ def images(self):
+ if not hasattr(self, "documents"):
+ Document = apps.get_model("ishtar_common", "Document")
+ return Document.objects.none()
+ return (
+ self.documents.filter(image__isnull=False).exclude(image="").order_by("pk")
+ )
+
+ @property
+ def images_number(self):
+ return self.images.count()
+
+ @property
+ def images_without_main_image(self):
+ if not hasattr(self, "main_image") or not hasattr(self, "documents"):
+ return self.images
+ if not self.main_image:
+ return (
+ self.documents.filter(image__isnull=False)
+ .exclude(image="")
+ .order_by("pk")
+ )
+ return (
+ self.documents.filter(image__isnull=False)
+ .exclude(image="")
+ .exclude(pk=self.main_image.pk)
+ .order_by("pk")
+ )
+
+ @property
+ def pdf_attached(self):
+ for document in self.documents.filter(
+ Q(associated_file__isnull=False) | Q(source__associated_file__isnull=False)
+ ).all():
+ return document.pdf_attached
+
+ def get_extra_actions(self, request):
+ """
+ For sheet template: return "Add document / image" action
+ """
+ # url, base_text, icon, extra_text, extra css class, is a quick action
+ try:
+ actions = super(DocumentItem, self).get_extra_actions(request)
+ except AttributeError:
+ actions = []
+
+ if not hasattr(self, "SLUG"):
+ return actions
+
+ can_add_doc = self.can_do(request, "add_document")
+ if can_add_doc and (
+ not hasattr(self, "is_locked") or not self.is_locked(request.user)
+ ):
+ actions += [
+ (
+ reverse("create-document") + "?{}={}".format(self.SLUG, self.pk),
+ _("Add document/image"),
+ "fa fa-plus",
+ _("doc./image"),
+ "",
+ False,
+ )
+ ]
+ return actions
+
+
+def clean_duplicate_association(document, related_item, action):
+ profile = get_current_profile()
+ if not profile.clean_redundant_document_association or action != "post_add":
+ return
+ class_name = related_item.__class__.__name__
+ if class_name not in ("Find", "ContextRecord", "Operation"):
+ return
+ if class_name == "Find":
+ for cr in document.context_records.filter(
+ base_finds__find__pk=related_item.pk
+ ).all():
+ document.context_records.remove(cr)
+ for ope in document.operations.filter(
+ context_record__base_finds__find__pk=related_item.pk
+ ).all():
+ document.operations.remove(ope)
+ return
+ if class_name == "ContextRecord":
+ for ope in document.operations.filter(context_record__pk=related_item.pk).all():
+ document.operations.remove(ope)
+ if document.finds.filter(base_finds__context_record=related_item.pk).count():
+ document.context_records.remove(related_item)
+ return
+ if class_name == "Operation":
+ if document.context_records.filter(operation=related_item.pk).count():
+ document.operations.remove(related_item)
+ return
+ if document.finds.filter(
+ base_finds__context_record__operation=related_item.pk
+ ).count():
+ document.operations.remove(related_item)
+ return
+
+
+def document_attached_changed(sender, **kwargs):
+ # associate a default main image
+ instance = kwargs.get("instance", None)
+ model = kwargs.get("model", None)
+ pk_set = kwargs.get("pk_set", None)
+ if not instance or not model:
+ return
+
+ if hasattr(instance, "documents"):
+ items = [instance]
+ else:
+ if not pk_set:
+ return
+ try:
+ items = [model.objects.get(pk=pk) for pk in pk_set]
+ except model.DoesNotExist:
+ return
+
+ for item in items:
+ clean_duplicate_association(instance, item, kwargs.get("action", None))
+ for doc in item.documents.all():
+ doc.regenerate_all_ids()
+ q = item.documents.filter(image__isnull=False).exclude(image="")
+ if item.main_image:
+ if q.filter(pk=item.main_image.pk).count():
+ return
+ # the association has disappear not the main image anymore
+ item.main_image = None
+ item.skip_history_when_saving = True
+ item.save()
+ if not q.count():
+ return
+ # by default get the lowest pk
+ item.main_image = q.order_by("pk").all()[0]
+ item.skip_history_when_saving = True
+ item.save()
+
+
class NumberManager(models.Manager):
def get_by_natural_key(self, number):
return self.get(number=number)
@@ -2927,7 +3096,8 @@ class TownManager(models.Manager):
return self.get(numero_insee=numero_insee, year=year)
-class Town(GeographicItem, Imported, models.Model):
+class Town(GeographicItem, Imported, DocumentItem, models.Model):
+ SLUG = "town"
name = models.CharField(_("Name"), max_length=100)
surface = models.IntegerField(_("Surface (m2)"), blank=True, null=True)
center = models.PointField(
@@ -2956,6 +3126,17 @@ class Town(GeographicItem, Imported, models.Model):
cached_label = models.CharField(
_("Cached name"), max_length=500, null=True, blank=True, db_index=True
)
+ documents = models.ManyToManyField(
+ "Document", related_name="towns", verbose_name=_("Documents"), blank=True
+ )
+ main_image = models.ForeignKey(
+ "Document",
+ related_name="main_image_towns",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Main image"),
+ blank=True,
+ null=True,
+ )
objects = TownManager()
class Meta:
@@ -3085,6 +3266,12 @@ class Town(GeographicItem, Imported, models.Model):
if self.numero_insee != old_num:
return True
+ def _get_base_image_path(self):
+ if self.numero_insee and len(self.numero_insee) == 5:
+ prefix = self.numero_insee[:2]
+ return f"{self.SLUG}/{prefix}"
+ return self.SLUG
+
def _generate_cached_label(self):
cached_label = self.name
if settings.COUNTRY == "fr" and self.numero_insee:
@@ -3112,6 +3299,7 @@ def post_save_town(sender, **kwargs):
post_save.connect(post_save_town, sender=Town)
m2m_changed.connect(geodata_attached_changed, sender=Town.geodata.through)
+m2m_changed.connect(document_attached_changed, sender=Town.documents.through)
def town_child_changed(sender, **kwargs):
@@ -3563,175 +3751,6 @@ class DashboardFormItem:
return q.order_by("pk").distinct("pk").count()
-class DocumentItem:
- ALT_NAMES = {
- "documents__image__isnull": SearchAltName(
- pgettext_lazy("key for text search", "has-image"),
- "documents__image__isnull",
- ),
- "documents__associated_url__isnull": SearchAltName(
- pgettext_lazy("key for text search", "has-url"),
- "documents__associated_url__isnull",
- ),
- "documents__associated_file__isnull": SearchAltName(
- pgettext_lazy("key for text search", "has-attached-file"),
- "documents__associated_file__isnull",
- ),
- }
-
- def documents_list(self) -> list:
- Document = apps.get_model("ishtar_common", "Document")
- return self.get_associated_main_item_list("documents", Document)
-
- def public_representation(self):
- images = []
- if getattr(self, "main_image", None):
- images.append(self.main_image.public_representation())
- images += [
- image.public_representation()
- for image in self.images_without_main_image.all()
- ]
- return {"images": images}
-
- @property
- def images(self):
- if not hasattr(self, "documents"):
- Document = apps.get_model("ishtar_common", "Document")
- return Document.objects.none()
- return (
- self.documents.filter(image__isnull=False).exclude(image="").order_by("pk")
- )
-
- @property
- def images_number(self):
- return self.images.count()
-
- @property
- def images_without_main_image(self):
- if not hasattr(self, "main_image") or not hasattr(self, "documents"):
- return self.images
- if not self.main_image:
- return (
- self.documents.filter(image__isnull=False)
- .exclude(image="")
- .order_by("pk")
- )
- return (
- self.documents.filter(image__isnull=False)
- .exclude(image="")
- .exclude(pk=self.main_image.pk)
- .order_by("pk")
- )
-
- @property
- def pdf_attached(self):
- for document in self.documents.filter(
- Q(associated_file__isnull=False) | Q(source__associated_file__isnull=False)
- ).all():
- return document.pdf_attached
-
- def get_extra_actions(self, request):
- """
- For sheet template: return "Add document / image" action
- """
- # url, base_text, icon, extra_text, extra css class, is a quick action
- try:
- actions = super(DocumentItem, self).get_extra_actions(request)
- except AttributeError:
- actions = []
-
- if not hasattr(self, "SLUG"):
- return actions
-
- can_add_doc = self.can_do(request, "add_document")
- if can_add_doc and (
- not hasattr(self, "is_locked") or not self.is_locked(request.user)
- ):
- actions += [
- (
- reverse("create-document") + "?{}={}".format(self.SLUG, self.pk),
- _("Add document/image"),
- "fa fa-plus",
- _("doc./image"),
- "",
- False,
- )
- ]
- return actions
-
-
-def clean_duplicate_association(document, related_item, action):
- profile = get_current_profile()
- if not profile.clean_redundant_document_association or action != "post_add":
- return
- class_name = related_item.__class__.__name__
- if class_name not in ("Find", "ContextRecord", "Operation"):
- return
- if class_name == "Find":
- for cr in document.context_records.filter(
- base_finds__find__pk=related_item.pk
- ).all():
- document.context_records.remove(cr)
- for ope in document.operations.filter(
- context_record__base_finds__find__pk=related_item.pk
- ).all():
- document.operations.remove(ope)
- return
- if class_name == "ContextRecord":
- for ope in document.operations.filter(context_record__pk=related_item.pk).all():
- document.operations.remove(ope)
- if document.finds.filter(base_finds__context_record=related_item.pk).count():
- document.context_records.remove(related_item)
- return
- if class_name == "Operation":
- if document.context_records.filter(operation=related_item.pk).count():
- document.operations.remove(related_item)
- return
- if document.finds.filter(
- base_finds__context_record__operation=related_item.pk
- ).count():
- document.operations.remove(related_item)
- return
-
-
-def document_attached_changed(sender, **kwargs):
- # associate a default main image
- instance = kwargs.get("instance", None)
- model = kwargs.get("model", None)
- pk_set = kwargs.get("pk_set", None)
- if not instance or not model:
- return
-
- if hasattr(instance, "documents"):
- items = [instance]
- else:
- if not pk_set:
- return
- try:
- items = [model.objects.get(pk=pk) for pk in pk_set]
- except model.DoesNotExist:
- return
-
- for item in items:
- clean_duplicate_association(instance, item, kwargs.get("action", None))
- for doc in item.documents.all():
- doc.regenerate_all_ids()
- q = item.documents.filter(image__isnull=False).exclude(image="")
- if item.main_image:
- if q.filter(pk=item.main_image.pk).count():
- return
- # the association has disappear not the main image anymore
- item.main_image = None
- item.skip_history_when_saving = True
- item.save()
- if not q.count():
- return
- # by default get the lowest pk
- item.main_image = q.order_by("pk").all()[0]
- item.skip_history_when_saving = True
- item.save()
-
-
class QuickAction:
"""
Quick action available from tables
diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py
index 7328a5f95..4e450c3f8 100644
--- a/ishtar_common/tests.py
+++ b/ishtar_common/tests.py
@@ -3821,9 +3821,41 @@ class DocumentTest(TestCase):
self.find2.base_finds.add(bf2)
self.st1 = models.SourceType.objects.create(label="Report", code="REP")
self.st2 = models.SourceType.objects.create(label="Illustration", code="ILL")
+ self.town = models.Town.objects.create(name="Daisy town", numero_insee="59134")
self.username, self.password, self.user = create_superuser()
+ def test_create_form(self):
+ nb_doc = models.Document.objects.count()
+ c = Client()
+ url = reverse("create-document")
+ response = c.get(url)
+ self.assertEqual(response.status_code, 302)
+
+ c.login(username=self.username, password=self.password)
+ response = c.get(url)
+ self.assertEqual(response.status_code, 200)
+
+ posted = {
+ "authors": [],
+ "title": "A document",
+ "operations": [str(self.ope1.pk)],
+ "towns": [str(self.town.pk)],
+ }
+ response = c.post(url, posted)
+ new_child_document = self.ope1.documents.order_by("-pk").all()[0]
+ self.assertEqual(nb_doc + 1, models.Document.objects.count())
+ self.assertRedirects(
+ response,
+ "/document/edit/?open_item={}".format(
+ new_child_document.pk
+ ),
+ )
+ self.assertIn(
+ self.town.pk,
+ list(new_child_document.towns.values_list("pk", flat=True).all())
+ )
+
def test_custom_index(self):
profile, created = models.IshtarSiteProfile.objects.get_or_create(
slug="default", active=True
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index ad7e22019..0fe9c1716 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -339,6 +339,7 @@ urlpatterns += [
views.new_person_noorga,
name="new-person-noorga",
),
+ url(r"autocomplete-area/$", views.autocomplete_area, name="autocomplete-area"),
url(r"autocomplete-user/$", views.autocomplete_user, name="autocomplete-user"),
url(
r"autocomplete-ishtaruser/$",
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index ba205abf3..b469df12d 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -823,6 +823,23 @@ def autocomplete_person(
return HttpResponse(data, content_type="text/plain")
+def autocomplete_area(request):
+ if not request.GET.get("term"):
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term")
+ q = unicodedata.normalize("NFKD", q).encode("ascii", "ignore").decode()
+ query = Q()
+ for q in q.split(" "):
+ extra = Q(label__icontains=q)
+ query = query & extra
+ limit = 20
+ areas = models.Area.objects.filter(query).distinct()[:limit]
+ data = json.dumps(
+ [{"id": area.pk, "value": str(area)} for area in areas]
+ )
+ return HttpResponse(data, content_type="text/plain")
+
+
def autocomplete_department(request):
if not request.GET.get("term"):
return HttpResponse("[]", content_type="text/plain")