2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2024-11-25 08:41:51 +00:00
troggle/core/forms.py

254 lines
12 KiB
Python
Raw Normal View History

2011-07-11 02:10:22 +01:00
import django.forms as forms
from django.forms import ModelForm
from django.forms.models import modelformset_factory
2023-01-19 18:35:56 +00:00
2023-01-29 16:47:46 +00:00
from troggle.core.models.caves import Cave, CaveAndEntrance, Entrance
2023-01-19 18:35:56 +00:00
from troggle.core.views.editor_helpers import HTMLarea
from django.core.exceptions import ValidationError
# from tinymce.widgets import TinyMCE
import re
2011-07-11 02:10:22 +01:00
"""These are all the class-based Forms used by troggle.
2022-03-22 02:22:15 +00:00
There are other, simpler, upload forms in view/uploads.py
2023-07-31 13:49:54 +01:00
class-based forms are quicker to set up (for Django experts) but
2023-11-02 19:05:08 +00:00
are more difficult to maintain (or even begin to understand) by non-Django experts.
Notes to self, as I try to work out what the hell is going on:
Note that HTMLarea invokes a widget which sets a CSS class which calls javascript in
templates/html_editor_scripts_css.html - which imports jquery and codemirror directly, without
declaring it anywhere or locally installing it. (!)
"""
todo = """
"""
2021-04-13 01:37:42 +01:00
2021-04-21 19:08:42 +01:00
class CaveForm(ModelForm):
"""Only those fields for which we want to override defaults are listed here
2023-09-11 18:38:14 +01:00
the other fields of the class Cave are present on the form, but use the default presentation style
"""
2023-11-14 13:55:11 +00:00
unofficial_number= forms.CharField(required=False,
label="Unofficial Number used to construct internal identifiers",
widget=forms.TextInput(
attrs={"size": "45", "placeholder": "2035-ZB-03"}))
official_name = forms.CharField(required=False,
label="Name:",widget=forms.TextInput(
attrs={"size": "45", "placeholder": "ideally official name in German, but any name is OK"}))
underground_description = forms.CharField(
required=False,
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}),
)
explorers = forms.CharField(
required=False,
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}),
)
equipment = forms.CharField(
required=False,
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}),
)
survey = forms.CharField(
required=False,
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}),
)
# survey = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
2023-11-14 13:55:11 +00:00
kataster_status = forms.CharField(required=False,
label = "Kataster status, see below",
widget=forms.TextInput(attrs={"placeholder": "see example below"})
)
kataster_code = forms.CharField(required=False,
label = "Kataster code, see below",
widget=forms.TextInput(attrs={"placeholder": "see example below"})
)
underground_centre_line = forms.CharField(
required=False,
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}),
)
notes = forms.CharField(
required=False,
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}),
)
references = forms.CharField(
required=False,
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}),
)
2023-11-14 13:55:11 +00:00
description_file = forms.CharField(required=False, label="Path of top-level description file for this cave, when a separate file is used. Otherwise blank.", widget=forms.TextInput(attrs={"size": "45","placeholder": "usually blank"}), help_text="")
survex_file = forms.CharField(
required=False, label="Survex file eg. caves-1623/000/000.svx", widget=forms.TextInput(attrs={"size": "45"})
)
2023-11-14 13:55:11 +00:00
length = forms.CharField(required=False, label="Length (m)", widget=forms.TextInput(attrs={"placeholder": "usually blank"}))
depth = forms.CharField(required=False, label="Depth (m)", widget=forms.TextInput(attrs={"placeholder": "usually blank"}))
extent = forms.CharField(required=False, label="Extent (m)", widget=forms.TextInput(attrs={"placeholder": "usually blank"}))
subarea = forms.CharField(required=False, label="Subarea", widget=forms.TextInput(attrs={"placeholder": "usually blank, archaic"}))
#cave_slug = forms.CharField()
class Meta:
model = Cave
2023-11-03 14:54:57 +00:00
exclude = ("filename","url")
2023-11-14 13:55:11 +00:00
field_order = ['unofficial_number', 'kataster_number', 'official_name', 'underground_description', 'survey', 'underground_centre_line', 'explorers', 'equipment', 'notes', 'references', 'description_file', 'survex_file', 'areacode', 'length', 'depth', 'extent',
'kataster_code', 'kataster_status' ]
2023-09-11 18:38:14 +01:00
def clean_cave_slug(self):
if self.cleaned_data["cave_slug"] == "":
2023-09-11 18:38:14 +01:00
myArea = self.cleaned_data["areacode"]
if self.data["kataster_number"]:
cave_slug = f"{myArea}-{self.cleaned_data['kataster_number']}"
else:
cave_slug = f"{myArea}-{self.cleaned_data['unofficial_number']}"
else:
cave_slug = self.cleaned_data["cave_slug"]
# Converting a PENDING cave to a real cave by saving this form
print("EEE", cave_slug.replace("-PENDING-", "-"))
return cave_slug.replace("-PENDING-", "-")
def clean(self):
cleaned_data = super(CaveForm, self).clean() # where is this code hidden? How does this work??
if self.data.get("kataster_number") == "" and self.data.get("unofficial_number") == "":
self._errors["unofficial_number"] = self.error_class(
["Either the kataster or unoffical number is required."]
)
# if self.cleaned_data.get("kataster_number") != "" and self.cleaned_data.get("official_name") == "":
# self._errors["official_name"] = self.error_class(["This field is required when there is a kataster number."])
2023-09-11 18:38:14 +01:00
if cleaned_data.get("url") == []:
self._errors["url"] = self.error_class(["This field is required."])
if cleaned_data.get("url") and cleaned_data.get("url").startswith("/"):
self._errors["url"] = self.error_class(["This field cannot start with a /."])
return cleaned_data
class EntranceForm(ModelForm):
"""Only those fields for which we want to override defaults are listed here
2023-07-26 15:38:19 +01:00
the other fields are present on the form, but use the default presentation style
"""
2023-11-14 13:55:11 +00:00
name = forms.CharField(required=False, widget=forms.TextInput(attrs={"size": "45", "placeholder": "usually leave this blank"}))
entrance_description = forms.CharField(
required=False,
2023-07-26 15:38:19 +01:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}),
)
explorers = forms.CharField(required=False, widget=forms.TextInput(attrs={"size": "45"}))
# explorers = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
map_description = forms.CharField(
2023-11-14 13:55:11 +00:00
label="Map (is this used?)",
required=False,
2023-07-26 15:38:19 +01:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}),
)
location_description = forms.CharField(
2023-11-14 13:55:11 +00:00
label="Location",
required=False,
2023-07-26 15:38:19 +01:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}),
)
lastvisit = forms.CharField(
2023-11-14 13:55:11 +00:00
required=False, widget=forms.TextInput(attrs={"size": "10"}), label="Last visit date, e.g. 2023-07-11"
)
approach = forms.CharField(
required=False,
2023-07-26 15:38:19 +01:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}),
)
underground_description = forms.CharField(
required=False,
2023-07-26 15:38:19 +01:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}),
)
photo = forms.CharField(
2023-11-14 13:55:11 +00:00
label="Photos (use 'image' button)",
required=False,
2023-11-14 13:55:11 +00:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Use button on right to add HTML link"}),
)
marking_comment = forms.CharField(
2023-11-14 13:55:11 +00:00
label="Marking text",
required=False,
2023-11-14 13:55:11 +00:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter exact tag text, e.g. 'CUCC 2035 ZB-03'"}),
)
findability_description = forms.CharField(
required=False,
2023-11-14 13:55:11 +00:00
label="How to find it",
2023-07-26 15:38:19 +01:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}),
)
other_description = forms.CharField(
2023-11-14 13:55:11 +00:00
label="Other comments",
required=False,
2023-11-14 13:55:11 +00:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Usually blank"}),
)
bearings = forms.CharField(
2023-11-14 13:55:11 +00:00
label="Bearings (obsolete)",
required=False,
2023-11-14 13:55:11 +00:00
widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Usually blank"}),
2023-07-26 15:38:19 +01:00
)
tag_station = forms.CharField(
required=False,
2023-11-14 13:55:11 +00:00
widget=forms.TextInput(attrs={"size": "50","placeholder": "e.g. 1623.t2035-zb-03a"}),
label="Tag station: Survex station id, e.g. 1623.p2023-aa-01"
2023-07-26 15:38:19 +01:00
)
other_station = forms.CharField(
required=False,
2023-11-14 13:55:11 +00:00
widget=forms.TextInput(attrs={"size": "50","placeholder": "e.g. 1623.p2035-zb-03c"}),
label="Other station: Survex station id, e.g. 1623.gps2018-aa-01"
)
2023-10-11 22:25:24 +01:00
2023-07-26 15:38:19 +01:00
lat_wgs84 = forms.CharField(
2023-11-14 13:55:11 +00:00
required=False, widget=forms.TextInput(attrs={"size": "10","placeholder": "e.g. 47.123456"}),
label="Latitude (WSG84) - if no other location"
2023-07-26 15:38:19 +01:00
)
long_wgs84 = forms.CharField(
2023-11-14 13:55:11 +00:00
required=False, widget=forms.TextInput(attrs={"size": "10","placeholder": "e.g. 13.123456"}),
label="Longitude (WSG84) - if no other location"
2023-07-26 15:38:19 +01:00
)
2023-10-11 22:58:20 +01:00
alt = forms.CharField(required=False, label="Altitude (m) - from GPS if you have it, but let it settle.")
2023-11-14 13:55:11 +00:00
# url = forms.CharField(required=False, label="URL [usually blank]", widget=forms.TextInput(attrs={"size": "45"}))
2023-11-14 13:55:11 +00:00
field_order = ['name', 'entrance_description', 'explorers', 'map_description', 'location_description', 'lastvisit', 'approach', 'underground_description', 'photo', 'marking_comment', 'findability_description', 'other_description', 'bearings', 'tag_station', 'other_station', 'easting', 'northing', 'lat_wgs84', 'long_wgs84', 'alt']
2023-04-30 21:41:17 +01:00
class Meta:
model = Entrance
exclude = (
"cached_primary_slug",
2023-11-14 13:55:11 +00:00
"filename",
"slug"
)
2015-09-16 01:52:45 +01:00
def clean(self):
if self.cleaned_data.get("url").startswith("/"):
self._errors["url"] = self.error_class(["This field cannot start with a /."])
2015-09-16 01:52:45 +01:00
return self.cleaned_data
2023-03-28 20:30:00 +01:00
# This next line is called from the templates/edit_cave.html template.
2022-03-17 00:41:29 +00:00
# This is sufficient to create an entire entry for for the cave fields automatically
2020-08-02 23:53:35 +01:00
# http://localhost:8000/cave/new/
2023-02-10 00:05:04 +00:00
# using django built-in Deep Magic. https://docs.djangoproject.com/en/dev/topics/forms/modelforms/
2022-03-17 00:41:29 +00:00
# for forms which map directly onto a Django Model
CaveAndEntranceFormSet = modelformset_factory(CaveAndEntrance, exclude=("cave",))
2023-03-28 20:30:00 +01:00
# This is used only in edit_entrance() in views/caves.py
class EntranceLetterForm(ModelForm):
"""Form to link entrances to caves, along with an entrance number.
Nb. The relationship between caves and entrances has historically been a many to many relationship.
With entrances gaining new caves and letters when caves are joined.
"""
2023-11-05 13:20:45 +00:00
# This only needs to be required=True for the second and subsequent entrances, not the first. Tricky.
entranceletter = forms.CharField(required=False, widget=forms.TextInput(attrs={"size": "2"}))
class Meta:
model = CaveAndEntrance
exclude = ("cave", "entrance")
def full_clean(self):
super(EntranceLetterForm, self).full_clean()
try:
self.instance.validate_unique()
except forms.ValidationError as e:
self._update_errors(e)