summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2023-09-13 12:59:20 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2024-04-16 16:38:32 +0200
commit3e9cfaeaed2eced1e3f9b2bd80f2f93b730d06e9 (patch)
treef340b493ce89008b1999a6767da6ee8d58dabf79 /ishtar_common
parentc2764f756035048756866fa4e4d4c75908e5b392 (diff)
downloadIshtar-3e9cfaeaed2eced1e3f9b2bd80f2f93b730d06e9.tar.bz2
Ishtar-3e9cfaeaed2eced1e3f9b2bd80f2f93b730d06e9.zip
✨ Pre-import form: form choice field - black format
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms.py27
-rw-r--r--ishtar_common/forms_common.py252
2 files changed, 179 insertions, 100 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py
index 0f1263bef..c560dc5ec 100644
--- a/ishtar_common/forms.py
+++ b/ishtar_common/forms.py
@@ -681,7 +681,9 @@ class IshtarForm(forms.Form, BSForm):
# to manage translation
def __init__(self, *args, **kwargs):
- super(IshtarForm, self).__init__(*args, **kwargs)
+ self._headers = {} # used for dynamic headers
+ self._types = [] # used for dynamic types
+ super().__init__(*args, **kwargs)
profile = None
if self.PROFILE_FILTER or self.SITE_KEYS:
profile = models.get_current_profile()
@@ -694,8 +696,6 @@ class IshtarForm(forms.Form, BSForm):
self.fields.pop(field_key)
if getattr(self, "confirm", False):
return
- for field in self.TYPES:
- self._init_type(field)
if self.SITE_KEYS:
field_keys = list(self.fields.keys())
for site_key in list(self.SITE_KEYS.keys()):
@@ -722,8 +722,14 @@ class IshtarForm(forms.Form, BSForm):
continue
for option, value in options.items():
setattr(self.fields[field_name].widget, option, value)
+ self._init_types()
self._post_init()
+ def _init_types(self):
+ type_lst = self._types or self.TYPES
+ for field in type_lst:
+ self._init_type(field)
+
def _init_type(self, field):
if field.key not in self.fields:
return
@@ -731,6 +737,8 @@ class IshtarForm(forms.Form, BSForm):
self.fields[field.key].help_text = field.get_help()
def get_headers(self):
+ if self._headers:
+ return self._headers
return self.HEADERS
def headers(self, key):
@@ -775,10 +783,11 @@ class IshtarForm(forms.Form, BSForm):
conditional_fields = self.CONDITIONAL_FIELDS
if hasattr(self, "get_conditional_fields"):
conditional_fields = self.get_conditional_fields()
- if not conditional_fields or not self.TYPES:
+ type_lst = self._types or self.TYPES
+ if not conditional_fields or not type_lst:
return
- type_dict = dict([(typ.key, typ.model) for typ in self.TYPES])
+ type_dict = dict([(typ.key, typ.model) for typ in type_lst])
html = ""
for condition, target_names in conditional_fields:
condition_field, condition_attr, condition_val = condition
@@ -851,12 +860,13 @@ class IshtarForm(forms.Form, BSForm):
all_values,
) = self.get_conditional_filter_fields()
- types = [typ.key for typ in self.TYPES]
+ type_lst = self._types or self.TYPES
+ type_lst = [typ.key for typ in type_lst]
html = ""
outputs = set()
for input_key in conditional_fields:
- if input_key not in types:
+ if input_key not in type_lst:
continue
name = input_key
if self.prefix:
@@ -1159,7 +1169,8 @@ class ManageOldType(IshtarForm):
self.init_data[k].append(val)
self.init_data = MultiValueDict(self.init_data)
super(ManageOldType, self).__init__(*args, **kwargs)
- for field in self.TYPES:
+ type_lst = self._types or self.TYPES
+ for field in type_lst:
self._init_type(field)
def _init_type(self, field):
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 1b59206a6..3e3488ae9 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -30,13 +30,16 @@ from urllib.parse import urlparse, quote
import zipfile
from django import forms
+from django.apps import apps
from django.conf import settings
from django.contrib.auth import password_validation
from django.contrib.auth.models import User
-from django.contrib.auth.forms import UsernameField, \
- AuthenticationForm as AuthAuthenticationForm, \
- PasswordChangeForm as AuthPasswordChangeForm, \
- SetPasswordForm as AuthSetPasswordForm
+from django.contrib.auth.forms import (
+ UsernameField,
+ AuthenticationForm as AuthAuthenticationForm,
+ PasswordChangeForm as AuthPasswordChangeForm,
+ SetPasswordForm as AuthSetPasswordForm,
+)
from django.core import validators
from django.core.exceptions import ObjectDoesNotExist
from django.core.files import File
@@ -73,8 +76,12 @@ from .forms import (
LockForm,
)
from ishtar_common.data_importer import ImporterError
-from ishtar_common.utils import is_downloadable, clean_session_cache, max_size_help, \
- reverse_coordinates
+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
@@ -138,14 +145,15 @@ def get_person_field(label=_("Person"), required=True, person_types=None):
class AuthenticationForm(AuthAuthenticationForm):
- username = UsernameField(widget=forms.TextInput(
- attrs={'autofocus': True, 'class': 'no-append'})
+ username = UsernameField(
+ widget=forms.TextInput(attrs={"autofocus": True, "class": "no-append"})
)
password = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput(
- attrs={'autocomplete': 'off', 'data-toggle': 'password'})
+ attrs={"autocomplete": "off", "data-toggle": "password"}
+ ),
)
@@ -154,14 +162,16 @@ class SetPasswordForm(AuthSetPasswordForm):
label=_("New password"),
strip=False,
help_text=password_validation.password_validators_help_text_html(),
- widget=forms.PasswordInput(attrs={'autocomplete': 'off',
- 'data-toggle': 'password'}),
+ widget=forms.PasswordInput(
+ attrs={"autocomplete": "off", "data-toggle": "password"}
+ ),
)
new_password2 = forms.CharField(
label=_("New password confirmation"),
strip=False,
- widget=forms.PasswordInput(attrs={'autocomplete': 'off',
- 'data-toggle': 'password'}),
+ widget=forms.PasswordInput(
+ attrs={"autocomplete": "off", "data-toggle": "password"}
+ ),
)
@@ -169,9 +179,9 @@ class PasswordChangeForm(SetPasswordForm, AuthPasswordChangeForm):
old_password = forms.CharField(
label=_("Old password"),
strip=False,
- widget=forms.PasswordInput(attrs={'autofocus': True, 'autocomplete': 'off',
- 'data-toggle': 'password'}),
-
+ widget=forms.PasswordInput(
+ attrs={"autofocus": True, "autocomplete": "off", "data-toggle": "password"}
+ ),
)
@@ -246,9 +256,9 @@ class BaseImportForm(IshtarForm, forms.ModelForm):
def _filter_importer_type(self):
self.fields["importer_type"].choices = [("", "--")] + [
(imp.pk, imp.name)
- for imp in models.ImporterType.objects.filter(available=True,
- is_import=True,
- type=self.importer_type)
+ for imp in models.ImporterType.objects.filter(
+ available=True, is_import=True, type=self.importer_type
+ )
]
def _filter_group(self, user):
@@ -294,9 +304,9 @@ class BaseImportForm(IshtarForm, forms.ModelForm):
def clean(self):
data = self.cleaned_data
if (
- data.get("conservative_import", None)
- and data.get("importer_type")
- and not data.get("importer_type").unicity_keys
+ data.get("conservative_import", None)
+ and data.get("importer_type")
+ and not data.get("importer_type").unicity_keys
):
raise forms.ValidationError(
_(
@@ -363,13 +373,13 @@ class NewImportForm(BaseImportForm):
zf.testzip()
except zipfile.BadZipFile:
raise forms.ValidationError(
- _("\"Associated images\" field must be a valid zip file.")
+ _('"Associated images" field must be a valid zip file.')
)
self._clean_csv(is_csv=True)
archive_required = self._need_archive(data)
if archive_required and (
- not data.get("imported_images", None) and
- not data.get("imported_images_link", None)
+ not data.get("imported_images", None)
+ and not data.get("imported_images_link", None)
):
raise forms.ValidationError(_("This importer need a document archive."))
return data
@@ -448,7 +458,9 @@ class NewImportGISForm(BaseImportForm):
raise forms.ValidationError("")
except forms.ValidationError:
raise forms.ValidationError(
- _("GIS file must be a zip containing a ShapeFile or GeoPackage file.")
+ _(
+ "GIS file must be a zip containing a ShapeFile or GeoPackage file."
+ )
)
return value
@@ -624,39 +636,70 @@ class TargetKeyForm(forms.ModelForm):
class PreImportForm(IshtarForm):
def __init__(self, *args, **kwargs):
- self.HEADERS = {}
+ self._headers = {}
+ self._types = []
self.import_item = kwargs.pop("import_item")
super().__init__(*args, **kwargs)
- readonly = self.import_item.state not in ("C", "AP", "A")
+ readonly = self.import_item.state not in ("C", "AP", "A")
for column in self.column_query.order_by("col_number"):
q = column.targets
if not q.count():
continue
target = q.all()[0]
- field_name, widget_name = FORMATER_WIDGETS_DCT[target.formater_type.formater_type]
+ field_name, widget_name = FORMATER_WIDGETS_DCT[
+ target.formater_type.formater_type
+ ]
attrs = {
"label": column.label,
"required": column.required,
}
- q = models.ImportColumnValue.objects.filter(column=column,
- import_item=self.import_item)
+ q = models.ImportColumnValue.objects.filter(
+ column=column, import_item=self.import_item
+ )
if q.count():
- attrs["initial"] = q.all()[0].value
+ value = q.all()[0].value
+ if target.formater_type.many_split:
+ if value.startswith("['") and value.endswith("']"):
+ value = value[2:-2].split("', '")
+ else:
+ value = ""
+ attrs["initial"] = value
if column.description:
attrs["help_text"] = column.description
if widget_name:
attrs["widget"] = getattr(forms, widget_name)
key = f"col_{- column.col_number}"
- self.fields[key] = getattr(forms, field_name)(
- **attrs
- )
+ form_field = getattr(forms, field_name)
+ if field_name == "ChoiceField":
+ if not target.formater_type.options:
+ continue
+ options = target.formater_type.options.split(".")
+ if len(options) == 1:
+ app = "ishtar_common"
+ else:
+ app = options[0]
+ model_name = options[-1]
+ try:
+ model = apps.get_model(app, model_name)
+ except LookupError:
+ continue
+ if target.formater_type.many_split:
+ form_field = widgets.Select2MultipleField
+ self._types.append(
+ FieldType(key, model, is_multiple=bool(target.formater_type.many_split))
+ )
+ self.fields[key] = form_field(**attrs)
if readonly:
self.fields[key].widget.attrs["readonly"] = True
- if not self.HEADERS:
- self.HEADERS[key] = FormHeader(self.import_item)
+ if not self._headers:
+ self._headers[key] = FormHeader(self.import_item)
if self.import_item.importer_type.pre_import_message:
- self.HEADERS[key].help_message = self.import_item.importer_type.pre_import_message
+ self._headers[
+ key
+ ].help_message = self.import_item.importer_type.pre_import_message
+ self._init_types()
+ self._post_init()
@property
def column_query(self):
@@ -668,8 +711,7 @@ class PreImportForm(IshtarForm):
if key not in self.cleaned_data:
continue
col_value, __ = models.ImportColumnValue.objects.get_or_create(
- column=column,
- import_item=self.import_item
+ column=column, import_item=self.import_item
)
col_value.value = self.cleaned_data[key]
col_value.save()
@@ -736,7 +778,9 @@ class OrganizationForm(ManageOldType, NewItemForm):
)
if dct["precise_town_id"]:
try:
- dct["precise_town_id"] = models.Town.objects.get(pk=dct["precise_town_id"]).pk
+ dct["precise_town_id"] = models.Town.objects.get(
+ pk=dct["precise_town_id"]
+ ).pk
except models.Town.DoesNotExist:
dct.pop("precise_town_id")
if not item:
@@ -1334,14 +1378,18 @@ class AccountForm(IshtarForm):
hidden_password = forms.CharField(
label=_("New password"),
max_length=128,
- widget=forms.PasswordInput(attrs={'autocomplete': 'off', 'data-toggle': 'password'}),
+ widget=forms.PasswordInput(
+ attrs={"autocomplete": "off", "data-toggle": "password"}
+ ),
required=False,
validators=[validators.MinLengthValidator(4)],
)
hidden_password_confirm = forms.CharField(
label=_("New password (confirmation)"),
max_length=128,
- widget=forms.PasswordInput(attrs={'autocomplete': 'off', 'data-toggle': 'password'}),
+ widget=forms.PasswordInput(
+ attrs={"autocomplete": "off", "data-toggle": "password"}
+ ),
required=False,
)
@@ -1396,9 +1444,7 @@ class AccountForm(IshtarForm):
_("You must provide a correct " "password.")
)
# check username unicity
- q = User.objects.filter(
- username=cleaned_data.get("username")
- )
+ q = User.objects.filter(username=cleaned_data.get("username"))
if cleaned_data.get("pk"):
q = q.exclude(ishtaruser__person__pk=cleaned_data.get("pk"))
if q.count():
@@ -1442,10 +1488,7 @@ class ProfileFormsetBase(FormSetWithDeleteSwitches):
for data in self.cleaned_data:
if not data.get("profile_type", None):
continue
- value = (
- data.get("profile_type", None),
- data.get("name", None)
- )
+ value = (data.get("profile_type", None), data.get("name", None))
if value in values:
raise forms.ValidationError(_("Choose different name for profiles."))
values.append(value)
@@ -2338,8 +2381,7 @@ class DocumentSelect(HistorySelect):
validators=[models.valid_id(Operation)],
)
operations__operation_type = forms.ChoiceField(
- label=_("Operation - type"),
- choices=[]
+ label=_("Operation - type"), choices=[]
)
operations__year = forms.IntegerField(label=_("Operation - year"))
context_record = forms.IntegerField(
@@ -2823,13 +2865,17 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
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."),
+ 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)
+ label="", required=True, widget=forms.HiddenInput, disabled=True
+ )
source_id = forms.IntegerField(
- label="", required=True, widget=forms.HiddenInput, disabled=True)
+ label="", required=True, widget=forms.HiddenInput, disabled=True
+ )
data_type = widgets.ModelChoiceField(
model=models.GeoDataType, label=_("Data type"), choices=[], required=False
)
@@ -2840,7 +2886,8 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
model=models.GeoProviderType, label=_("Provider"), choices=[], required=False
)
buffer = forms.FloatField(
- label=_("Buffer"), required=False,
+ label=_("Buffer"),
+ required=False,
widget=widgets.MeterCentimeterWidget,
)
buffer_type = widgets.ModelChoiceField(
@@ -2848,15 +2895,18 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
)
comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False)
estimated_error_x = forms.FloatField(
- label=_("Estimated error for X"), required=False,
+ label=_("Estimated error for X"),
+ required=False,
widget=widgets.MeterCentimeterWidget,
)
estimated_error_y = forms.FloatField(
- label=_("Estimated error for Y"), required=False,
+ label=_("Estimated error for Y"),
+ required=False,
widget=widgets.MeterCentimeterWidget,
)
estimated_error_z = forms.FloatField(
- label=_("Estimated error for Z"), required=False,
+ label=_("Estimated error for Z"),
+ required=False,
widget=widgets.MeterCentimeterWidget,
)
@@ -2869,12 +2919,21 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
class Meta:
model = models.GeoVectorData
- exclude = ["need_update", "imports", "cached_x", "cached_y", "cached_z",
- "source_content_type", "timestamp_label", "timestamp_geo"]
+ exclude = [
+ "need_update",
+ "imports",
+ "cached_x",
+ "cached_y",
+ "cached_z",
+ "source_content_type",
+ "timestamp_label",
+ "timestamp_geo"
+ ]
HEADERS = {
"related_items_ishtar_common_town": FormHeader(
- _("Related items"), collapse=True),
+ _("Related items"), collapse=True
+ ),
"name": FormHeader(_("Metadata")),
"geo_field": FormHeader(_("Geography")),
"buffer": FormHeader(_("Buffer"), collapse=True),
@@ -2911,8 +2970,9 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
if "too_many" in kwargs:
self.too_many = kwargs.pop("too_many")
self.user = None
- self.geom_type = kwargs.pop("geom_type") \
- if kwargs.get("geom_type", None) else None
+ self.geom_type = (
+ kwargs.pop("geom_type") if kwargs.get("geom_type", None) else None
+ )
if kwargs.get("user", None):
self.user = kwargs.pop("user")
instance = kwargs.get("instance", False)
@@ -2923,10 +2983,12 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
super().__init__(*args, **kwargs)
if back_url:
self.fields["back_url"] = forms.CharField(
- label="", required=False, widget=forms.HiddenInput, initial=back_url)
+ label="", required=False, widget=forms.HiddenInput, initial=back_url
+ )
if find_id:
self.fields["find_id"] = forms.CharField(
- label="", required=False, widget=forms.HiddenInput, initial=find_id)
+ label="", required=False, widget=forms.HiddenInput, initial=find_id
+ )
if not self.fields["import_key"].initial:
self.fields.pop("import_key")
if not self.source_content_type:
@@ -2951,7 +3013,7 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
for field_key, label in main_items_fields[related_key]:
disabled = False
if kwargs.get("initial", None) and kwargs["initial"].get(
- field_key, False
+ field_key, False
):
disabled = True
fields[field_key] = forms.BooleanField(
@@ -2976,9 +3038,12 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
extra_geo = ["buffer", "buffer_type"]
if self.geom_type == "coordinates":
geo_keys = [
- "x", "estimated_error_x",
- "y", "estimated_error_y",
- "z", "estimated_error_z",
+ "x",
+ "estimated_error_x",
+ "y",
+ "estimated_error_y",
+ "z",
+ "estimated_error_z",
"spatial_reference_system",
]
base_widget_attrs = {}
@@ -3038,16 +3103,22 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
if map_srid == 4326:
widget = widgets.ReversedOSMWidget
self.fields[keys[0]].widget = widget(
- attrs={"map_srid": map_srid,
- "geom_type": geom.geom_type,
- "cols": True})
+ attrs={
+ "map_srid": map_srid,
+ "geom_type": geom.geom_type,
+ "cols": True,
+ }
+ )
self.fields.pop("spatial_reference_system")
geo_keys = keys[:]
else:
geo_keys = [
- "x", "estimated_error_x",
- "y", "estimated_error_y",
- "z", "estimated_error_z",
+ "x",
+ "estimated_error_x",
+ "y",
+ "estimated_error_y",
+ "z",
+ "estimated_error_z",
"spatial_reference_system",
]
for geo_fields in self.GEO_FIELDS:
@@ -3074,21 +3145,17 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):
def clean(self):
cleaned_data = self.cleaned_data
- if cleaned_data.get("buffer", None) \
- and not cleaned_data.get("buffer_type", None):
- raise forms.ValidationError(
- _("If you set a buffer set a buffer type.")
- )
- if cleaned_data.get("buffer_type", None) \
- and not cleaned_data.get("buffer", None):
- raise forms.ValidationError(
- _("If you set a buffer type set a buffer.")
- )
+ if cleaned_data.get("buffer", None) and not cleaned_data.get(
+ "buffer_type", None
+ ):
+ raise forms.ValidationError(_("If you set a buffer set a buffer type."))
+ if cleaned_data.get("buffer_type", None) and not cleaned_data.get(
+ "buffer", None
+ ):
+ raise forms.ValidationError(_("If you set a buffer type set a buffer."))
if cleaned_data.get("point_3d"):
if "z" not in cleaned_data:
- raise forms.ValidationError(
- _("A value is expected for Z.")
- )
+ raise forms.ValidationError(_("A value is expected for Z."))
value = cleaned_data["point_3d"].ewkt
if "POINT Z" not in value:
value = value.replace("POINT", "POINT Z")
@@ -3154,7 +3221,7 @@ class PreGISForm(IshtarForm):
("multi_points", _("Multi-points")),
("multi_line", _("Multi-lines")),
("multi_polygon", _("Multi-polygons")),
- )
+ ),
)
HEADERS = {
"geom_type": FormHeader(_("Type")),
@@ -3167,4 +3234,5 @@ class PreGISForm(IshtarForm):
super().__init__(*args, **kwargs)
if back_url:
self.fields["back_url"] = forms.CharField(
- label="", required=False, widget=forms.HiddenInput, initial=back_url)
+ label="", required=False, widget=forms.HiddenInput, initial=back_url
+ )