diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2026-03-24 17:20:43 +0100 |
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2026-03-25 15:10:38 +0100 |
| commit | 357b31ed1526b0627e1fae90ae261a46ee28e322 (patch) | |
| tree | 8a976135beffab07f1a1b0d3106c96a85b8f916c | |
| parent | bd00a0b3db9b795907d709d163f7e8217f7c7671 (diff) | |
| download | Ishtar-357b31ed1526b0627e1fae90ae261a46ee28e322.tar.bz2 Ishtar-357b31ed1526b0627e1fae90ae261a46ee28e322.zip | |
✨ qualified biographical note/site actors - autocomplete forms and actor form
| -rw-r--r-- | archaeological_operations/forms.py | 22 | ||||
| -rw-r--r-- | ishtar_common/forms_common.py | 62 | ||||
| -rw-r--r-- | ishtar_common/urls.py | 8 | ||||
| -rw-r--r-- | ishtar_common/views.py | 34 |
4 files changed, 112 insertions, 14 deletions
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index ba59f4419..f25d9f2cc 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -31,7 +31,6 @@ from django.core import validators from django.db.models import Max from django.forms.formsets import formset_factory, DELETION_FIELD_NAME, \ TOTAL_FORM_COUNT -from django.utils.functional import lazy from django.utils.safestring import mark_safe from ishtar_common.utils import gettext_lazy as _, pgettext_lazy, parse_parcels @@ -46,9 +45,7 @@ from ishtar_common.forms import FinalForm, FormSet, \ from ishtar_common.forms_common import TownFormSet, get_town_field, TownForm from ishtar_common.models import valid_id, valid_ids, Person, Town, \ DocumentTemplate, Organization, get_current_profile, \ - person_type_pks_lazy, person_type_pk_lazy, organization_type_pks_lazy, \ - organization_type_pk_lazy, SpatialReferenceSystem, Area, \ - get_sra_agent_label, get_sra_agent_head_scientist_label, get_operator_label + SpatialReferenceSystem, Area, QualifiedBiographicalNote from ishtar_common.wizards import MultiValueDict from .widgets import ParcelWidget, SelectParcelWidget, OAWidget @@ -1316,6 +1313,7 @@ class SiteForm(CustomForm, ManageOldType): 'spatial_reference_system': SpatialReferenceSystem, 'cultural_attribution': models.CulturalAttributionType, 'collaborator': Person, + "actor": QualifiedBiographicalNote, 'discoverer': Person, "nature_of_site": models.NatureOfSiteType, "interpretation_level": models.InterpretationLevelType, @@ -1324,7 +1322,10 @@ class SiteForm(CustomForm, ManageOldType): "town": Town, "type": models.SiteType, } - base_models = ["period", "remain", "collaborator", "cultural_attribution", "town", "type"] + extra_form_modals = ["qualifiedbiographicalnote", "biographicalnote", "person", + "organization"] + base_models = ["period", "remain", "collaborator", "cultural_attribution", "town", + "type", "actor"] pk = forms.IntegerField(required=False, widget=forms.HiddenInput) reference = forms.CharField(label=_("Reference"), max_length=200) @@ -1332,7 +1333,11 @@ class SiteForm(CustomForm, ManageOldType): other_reference = forms.CharField(label=_("Other reference"), required=False) collaborator = widgets.Select2MultipleField( - model=Person, label=_("Collaborators"), required=False, remote=True) + model=Person, label=_("Collaborators"), required=False, + remote=True, new=True) + actor = widgets.Select2MultipleField( + model=QualifiedBiographicalNote, label=_("Actors"), required=False, + remote=True, new=True) description = forms.CharField(label=_("Description"), widget=forms.Textarea, required=False) public_description = forms.CharField(label=_("Public description"), widget=forms.Textarea, @@ -1390,11 +1395,6 @@ class SiteForm(CustomForm, ManageOldType): FieldType('discovery_status', models.SiteDiscoveryStatusType), ] - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - if 'collaborator' in self.fields: - self.fields['collaborator'].widget.attrs['full-width'] = True - def clean_reference(self): reference = self.cleaned_data['reference'] q = models.ArchaeologicalSite.objects.filter(reference=reference) diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index c782bc03d..d0b1183be 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -1522,6 +1522,68 @@ class BiographicalNoteEditForm(BiographicalNoteForm, IshtarForm): self.fields[k].initial = value +class QualifiedBiographicalNoteForm(ManageOldType, NewItemForm): + form_label = _("Actor") + form_admin_name = _("Actor - 010 - General") + form_slug = "qualifiedbiographicalnote-general" + extra_form_modals = ["biographical_note"] + associated_models = { + "biographical_note": models.BiographicalNote, + "qualification_type": models.QualifiedBiographicalNoteType + } + biographical_note = forms.IntegerField( + label=_("Biographical note"), + widget=widgets.JQueryAutoComplete( + reverse_lazy("autocomplete-biographicalnote"), + associated_model=models.BiographicalNote, + new=True, + ), + validators=[models.valid_id(models.BiographicalNote)], + required=True, + ) + qualification_type = forms.ChoiceField(label=_("Qualification type"), choices=[], + required=True) + TYPES = [ + FieldType("qualification_type", models.QualifiedBiographicalNoteType), + ] + + def save(self, user, item=None): + dct = self.cleaned_data + dct["history_modifier"] = user + for key in self.associated_models.keys(): + if key in dct: + if not dct[key]: + dct.pop(key) + else: + model = self.associated_models[key] + try: + dct[key] = model.objects.get(pk=dct[key]) + except model.DoesNotExist: + dct.pop(key) + # get data + data = {} + for k in list(dct.keys()): + if k.startswith("data__"): + v = dct.pop(k) + keys = k.split("__")[1:] + dct = generate_dict_from_list(keys, v) + data = update_data(data, dct) + + if not item: + item = models.QualifiedBiographicalNote.objects.create(**dct) + else: + for k in dct: + setattr(item, k, dct[k]) + item.save() + + # set data + if item.data or data: + data = update_data(item.data, data) + item.data = data + item.save() + return item + + class AccountForm(IshtarForm): form_label = _("Account") associated_models = {"pk": models.Person} diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index 3d91d7493..78b185ac7 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -527,6 +527,11 @@ urlpatterns += [ name="new-biographicalnote", ), re_path( + r"new-qualifiedbiographicalnote/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$", + views.new_qualifiedbiographicalnote, + name="new-qualifiedbiographicalnote", + ), + re_path( r"^biographicalnote-qa-edit/(?P<pks>[0-9-]+)?/$", check_permissions( ["ishtar_common.change_biographicalnote", @@ -610,6 +615,9 @@ urlpatterns += [ views.autocomplete_biographical_note, name="autocomplete-biographicalnote" ), + re_path(r"autocomplete-qualifiedbiographicalnote/$", + views.autocomplete_qualified_biographical_note, + name="autocomplete-qualifiedbiographicalnote"), re_path(r"changelog/(?:(?P<page>\d+)/)?", views.ChangelogView.as_view(), name="changelog"), re_path(r"person-merge/(?:(?P<page>\d+)/)?$", views.person_merge, name="person_merge"), re_path( diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 545c4a413..4e8376dfc 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -1171,7 +1171,7 @@ def autocomplete_author(request): def autocomplete_biographical_note(request): - query = get_autocomplete_query(request, "ishtar_common", "person") + query = get_autocomplete_query(request, "ishtar_common", "BiographicalNote") if query is None: return HttpResponse("[]", content_type="text/plain") q = request.GET.get("term", "") @@ -1187,8 +1187,31 @@ def autocomplete_biographical_note(request): | Q(denomination__unaccent__icontains=q) ) query = query & qu - users = models.BiographicalNote.objects.filter(query).distinct()[:limit] - data = json.dumps([{"id": user.pk, "value": str(user)} for user in users]) + items = models.BiographicalNote.objects.filter(query).distinct()[:limit] + data = json.dumps([{"id": item.pk, "value": str(item)} for item in items]) + return HttpResponse(data, content_type="text/plain") + + +def autocomplete_qualified_biographical_note(request): + query = get_autocomplete_query(request, "ishtar_common", "QualifiedBiographicalNote") + if query is None: + return HttpResponse("[]", content_type="text/plain") + q = request.GET.get("term", "") + limit = request.GET.get("limit", 20) + try: + limit = int(limit) + except ValueError: + return HttpResponseBadRequest() + for q in q.split(" "): + qu = ( + Q(biographical_note__last_name__unaccent__icontains=q) + | Q(biographical_note__first_name__unaccent__icontains=q) + | Q(biographical_note__denomination__unaccent__icontains=q) + | Q(qualification_type__label__unaccent__icontains=q) + ) + query = query & qu + items = models.QualifiedBiographicalNote.objects.filter(query).distinct()[:limit] + data = json.dumps([{"id": item.pk, "value": str(item)} for item in items]) return HttpResponse(data, content_type="text/plain") @@ -1220,6 +1243,11 @@ new_biographical_note = new_qa_item( models.BiographicalNote, forms.BiographicalNoteForm, page_name=_("New biographical note") ) +new_qualifiedbiographicalnote = new_qa_item( + models.QualifiedBiographicalNote, forms.QualifiedBiographicalNoteForm, + page_name=_("New actor") +) + get_person_for_account = get_item( models.Person, "get_person", |
