diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2022-05-22 20:31:19 +0200 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2022-12-12 12:21:00 +0100 | 
| commit | df8a001203e9e936ae5bae4e06f5631d87fb3ada (patch) | |
| tree | b7bece5905a4a433cbde9132bec669669f1c8ea0 /ishtar_common/forms_common.py | |
| parent | 3ff82007369b115406c2f2effbdfb13188167bb7 (diff) | |
| download | Ishtar-df8a001203e9e936ae5bae4e06f5631d87fb3ada.tar.bz2 Ishtar-df8a001203e9e936ae5bae4e06f5631d87fb3ada.zip | |
Geodata - geo forms: new forms - many adaptations
Diffstat (limited to 'ishtar_common/forms_common.py')
| -rw-r--r-- | ishtar_common/forms_common.py | 204 | 
1 files changed, 202 insertions, 2 deletions
| diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 6e9e11006..695638120 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -30,6 +30,7 @@ from urllib.parse import urlparse, quote  import zipfile  from django import forms +from django.contrib.gis import forms as gis_forms  from django.conf import settings  from django.contrib.auth.models import User  from django.contrib.contenttypes.models import ContentType @@ -71,7 +72,8 @@ from .forms import (      LockForm,  )  from ishtar_common.data_importer import ImporterError -from ishtar_common.utils import is_downloadable, clean_session_cache, max_size_help +from ishtar_common.utils import is_downloadable, clean_session_cache, max_size_help, \ +    reverse_coordinates  from archaeological_operations.models import Operation, OperationType  from archaeological_context_records.models import ContextRecord @@ -1972,7 +1974,7 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):              if cleaned_data.get(rel, None):                  return cleaned_data          raise forms.ValidationError( -            _("A document has to be attached at least " "to one item") +            _("A document has to be attached at least to one item")          )      def clean_publisher(self): @@ -2562,3 +2564,201 @@ class QRSearchForm(forms.Form):              os.makedirs(dest_dir)          shutil.move(filename, dest_dir)          return os.path.join(settings.MEDIA_URL, "tmp", base_filename) + + +class GISForm(forms.ModelForm, CustomForm, ManageOldType): +    form_label = _("Geo item") +    form_admin_name = _("Geo item - General") +    form_slug = "geoitem-general" + +    extra_form_modals = [] +    associated_models = { +        "data_type": models.GeoDataType, +        "origin": models.GeoOriginType, +        "provider": models.GeoProviderType, +    } + +    pk = forms.IntegerField(label="", required=False, widget=forms.HiddenInput) +    name = forms.CharField( +        label=_("Name"), +        required=False, +        validators=[validators.MaxLengthValidator(500)], +    ) +    import_key = forms.CharField( +        label=_("Import key"), +        required=False, +        disabled=True, +        help_text=_("An update via import corresponding to the source element and " +                    "this key will overwrite the data."), +    ) +    source_content_type_id = forms.IntegerField( +        label="", required=True, widget=forms.HiddenInput, disabled=True) +    source_id = forms.IntegerField( +        label="", required=True, widget=forms.HiddenInput, disabled=True) +    data_type = widgets.ModelChoiceField( +        model=models.GeoDataType, label=_("Data type"), choices=[], required=False +    ) +    origin = widgets.ModelChoiceField( +        model=models.GeoOriginType, label=_("Origin"), choices=[], required=False +    ) +    provider = widgets.ModelChoiceField( +        model=models.GeoProviderType, label=_("Provider"), choices=[], required=False +    ) +    comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) + +    TYPES = [ +        FieldType("origin", models.GeoOriginType), +        FieldType("data_type", models.GeoDataType), +        FieldType("provider", models.GeoProviderType), +    ] + +    class Meta: +        model = models.GeoVectorData +        exclude = ["need_update", "imports", "cached_x", "cached_y", "cached_z", +                   "point_3d"] + +    HEADERS = { +        "related_items_ishtar_common_town": FormHeader( +            _("Related items"), collapse=True), +        "name": FormHeader(_("Meta-data")), +        "geo_field": FormHeader(_("Geography")), +    } +    OPTIONS_PERMISSIONS = [ +        # field name, permission, options +        ("tags", ("ishtar_common.add_documenttag",), {"new": True}), +    ] + +    GEO_FIELDS = ( +        ("point_2d",), +        ("multi_points",), +        ("multi_line",), +        ("multi_polygon",), +        ("x", "z") +    ) + +    def __init__(self, *args, **kwargs): +        main_items_fields = {} +        if "main_items_fields" in kwargs: +            main_items_fields = kwargs.pop("main_items_fields") +        self.user = None +        if kwargs.get("user", None): +            self.user = kwargs.pop("user") +        instance = kwargs.get("instance", False) +        self.is_instancied = bool(instance) +        super(GISForm, self).__init__(*args, **kwargs) +        if not self.fields["import_key"].initial: +            self.fields.pop("import_key") +        self.source_content_type = kwargs.pop("source_content_type", None) +        self.source_id = kwargs.pop("source_id", None) +        if not self.source_content_type: +            self.fields.pop("source_content_type_id") +            self.fields.pop("source_id") +        else: +            self.fields["source_content_type_id"].initial = self.source_content_type +            self.fields["source_id"].initial = self.source_id +        self.geo_keys = [] +        if instance: +            for keys in self.GEO_FIELDS: +                if any(getattr(instance, key) for key in keys): +                    if keys[0] != "x": +                        map_srid = getattr(instance, keys[0]).srid or 4326 +                        widget = gis_forms.OSMWidget +                        if map_srid == 4326: +                            widget = widgets.ReversedOSMWidget +                        self.fields[keys[0]].widget = widget( +                            attrs={"map_srid": map_srid}) +                        self.fields.pop("spatial_reference_system") +                        self.geo_keys = keys[:] +                    else: +                        self.geo_keys = [ +                            "x", "estimated_error_x", +                            "y", "estimated_error_y", +                            "z", "estimated_error_z", +                            "spatial_reference_system", +                        ] +                    for geo_fields in self.GEO_FIELDS: +                        if geo_fields != keys: +                            for geo_field in geo_fields: +                                self.fields.pop(geo_field) +                                if geo_field == "x": +                                    self.fields.pop("estimated_error_x") +                                    self.fields.pop("y") +                                    self.fields.pop("estimated_error_y") +                                if geo_field == "z": +                                    self.fields.pop("estimated_error_z") +                    break +            if not self.geo_keys: +                # TODO.... +                pass + +        fields = OrderedDict() +        for related_key in models.GeoVectorData.RELATED_MODELS: +            model = models.GeoVectorData._meta.get_field(related_key).related_model +            fields[related_key] = widgets.Select2MultipleField( +                model=model, +                remote=True, +                label=model._meta.verbose_name_plural, +                required=False, +                style="width: 100%", +            ) +            if related_key in main_items_fields: +                for field_key, label in main_items_fields[related_key]: +                    disabled = False +                    if kwargs.get("initial", None) and kwargs["initial"].get( +                            field_key, False +                    ): +                        disabled = True +                    fields[field_key] = forms.BooleanField( +                        label=label, required=False, disabled=disabled +                    ) +        for k in self.geo_keys: +            fields[k] = self.fields[k] +        for k in self.fields: +            if k not in self.geo_keys: +                fields[k] = self.fields[k] +        self.fields = fields + +    def get_headers(self): +        headers = self.HEADERS.copy() +        if self.geo_keys: +            headers[self.geo_keys[0]] = headers.pop("geo_field") +        return headers + +    def clean(self): +        cleaned_data = self.cleaned_data +        if "x" not in self.geo_keys: +            # reverse... +            geo_value = cleaned_data[self.geo_keys[0]] +            if geo_value: +                if not isinstance(geo_value, str): +                    geo_value = geo_value.ewkt +                if geo_value.startswith("SRID=4326;"): +                    cleaned_data[self.geo_keys[0]] = reverse_coordinates(geo_value) +        for rel in models.GeoVectorData.RELATED_MODELS: +            if cleaned_data.get(rel, None): +                return cleaned_data +        raise forms.ValidationError( +            _("A geo item has to be attached at least to one item") +        ) + +    def save(self, commit=True): +        item = super().save(commit=commit) +        for related_key in models.GeoVectorData.RELATED_MODELS: +            related = getattr(item, related_key) +            initial = dict([(rel.pk, rel) for rel in related.all()]) +            new = [int(pk) for pk in sorted(self.cleaned_data.get(related_key, []))] +            for pk, value in initial.items(): +                if pk in new: +                    continue +                related.remove(value) +            for new_pk in new: +                related_item = related.model.objects.get(pk=new_pk) +                if new_pk not in initial.keys(): +                    related.add(related_item) +        item = models.GeoVectorData.objects.get(pk=item.pk) +        if self.user: +            item.history_creator = self.user +        item.history_modifier = self.user +        item.skip_history_when_saving = True +        item.save()  # resave to regen the attached items +        return item | 
