From 549c1649b4037cad11c5d7ae7ef24c10b90879e7 Mon Sep 17 00:00:00 2001
From: Philip Sargent
Date: Wed, 20 Jul 2022 14:44:56 +0300
Subject: [PATCH] QMs now have working url to survexfile & tick description
---
core/models/caves.py | 38 ++++++++++++++++++++++++++++++++------
core/views/caves.py | 23 ++++++++++++-----------
parsers/QMs.py | 37 ++++++++++++++++---------------------
parsers/survex.py | 5 +++--
templates/cave_qms.html | 23 ++++++++++++++++-------
templates/qm.html | 19 ++++++++++++-------
6 files changed, 91 insertions(+), 54 deletions(-)
diff --git a/core/models/caves.py b/core/models/caves.py
index e635023..ea312df 100644
--- a/core/models/caves.py
+++ b/core/models/caves.py
@@ -4,6 +4,7 @@ import datetime
import re
import json
import subprocess
+import operator
from collections import defaultdict
from pathlib import Path
@@ -149,7 +150,21 @@ class Cave(TroggleModel):
return str(self.slug())
def get_QMs(self):
- return QM.objects.filter(cave=self)
+ '''Searches for all QMs that reference this cave. Probably a better Django way to do this
+ '''
+ qms = QM.objects.filter(cave=self).order_by('expoyear', 'block__date') # a QuerySet, see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#order-by
+ return qms # a QuerySet
+ # undated = []
+ # dated = []
+ # qms = QM.objects.filter(cave=self) # a QuerySet
+ # for q in qms:
+ # if q.block:
+ # dated.append(q)
+ # else:
+ # undated.append(q)
+ # sortedqms = sorted(dated, key=operator.attrgetter('block.date')) # sort by date of survexblock the QM was defined in
+ # orderedqms = sorted(undated, key=operator.attrgetter('expoyear')) # sort by date of expoyear
+ # return orderedqms + sortedqms # a list, NOT a QuerySet
# def new_QM_number(self, year=datetime.date.today().year):
@@ -456,8 +471,8 @@ class QM(TroggleModel):
blockname=models.TextField(blank=True,null=True) # NB truncated copy of survexblock name
expoyear = models.CharField(max_length=4,blank=True, null=True) # could change to datetime if logbooks similarly chnaged
found_by = models.ForeignKey(LogbookEntry, related_name='QMs_found',blank=True, null=True,on_delete=models.SET_NULL )
- ticked = models.BooleanField(default=False) # for ticked QMs not atatched to a logbook entry
- ticked_off_by = models.ForeignKey(LogbookEntry, related_name='QMs_ticked_off',blank=True, null=True,on_delete=models.SET_NULL)
+ ticked = models.BooleanField(default=False) # for ticked QMs not attached to a logbook entry, should imply completion_description has text
+ ticked_off_by = models.ForeignKey(LogbookEntry, related_name='QMs_ticked_off',blank=True, null=True,on_delete=models.SET_NULL) # unused, ever?!
number = models.IntegerField(help_text="this is the sequential number in the year, only unique for CSV imports", )
GRADE_CHOICES=(
('A', 'A: Large obvious lead'),
@@ -493,9 +508,20 @@ class QM(TroggleModel):
blocknamestr = ""
#return f'{self.cave.slug()[5:]}-{self.expoyear}-{self.blockname}{self.number}{self.grade}'
return f'{cavestr}-{expoyearstr}-{blocknamestr}{self.number}{self.grade}'
-
- def newslug(self):
-
+
+ def get_completion_url(self):
+ '''assumes html file named is in same folder as cave description file
+ '''
+ cd = None
+ if self.completion_description:
+ try:
+ dir = Path(self.cave.url).parent
+ cd = dir / self.completion_description
+ except:
+ cd = None
+ return cd
+
+ def newslug(self):
qmslug = f'{str(self.cave)}-{self.expoyear}-{self.blockname}{self.number}{self.grade}'
return qmslug
diff --git a/core/views/caves.py b/core/views/caves.py
index 033d073..0e4b4e8 100644
--- a/core/views/caves.py
+++ b/core/views/caves.py
@@ -272,14 +272,12 @@ def cavepage(request, karea, subpath):
r = rendercave(request, cave, cave.slug())
return r
except NoReverseMatch:
- raise
- except:
- raise
message = f'Failed to render cave: {kpath} (it does exist and is unique) because of a Django URL resolution error. Check urls.py.'
return render(request,'errors/generic.html', {'message': message})
-
- # return rendercave(request, cave, cave.slug(), cave_id=cave_id)
-
+ except:
+ # anything else is a new problem. Add in specific error messages here as we discover new types of error
+ raise
+
def caveEntrance(request, slug):
try:
cave = Cave.objects.get(caveslug__slug = slug)
@@ -482,6 +480,7 @@ def qm(request,cave_id,qm_id,year,grade=None, blockname=None):
290 has several QMS with the same number, grade, year (2108) and first 8 chars of the survexblock. This crashes things.
'''
+
year=int(year)
if blockname == '':
@@ -492,12 +491,13 @@ def qm(request,cave_id,qm_id,year,grade=None, blockname=None):
qm=manyqms.get(number=qm_id,expoyear=year)
return render(request,'qm.html', {'qm': qm})
except QM.DoesNotExist:
- raise
+ #raise
return render(request,'errors/badslug.html', {'badslug': f'{cave_id=} {year=} {qm_id=} {blockname=}'})
else:
try:
qmslug = f'{cave_id}-{year}-{blockname=}{qm_id}{grade}'
+ print(f'{qmslug=}')
c=getCave(cave_id)
manyqms=c.get_QMs()
qmqs=manyqms.filter(expoyear=year, blockname=blockname, number=qm_id, grade=grade)
@@ -509,15 +509,16 @@ def qm(request,cave_id,qm_id,year,grade=None, blockname=None):
else:
qm=qmqs.get(expoyear=year, blockname=blockname, number=qm_id, grade=grade)
if qm:
- print(qm, f'{qmslug=}:{cave_id=} {year=} {qm_id=} {blockname=} {qm.expoyear=}')
+ print(qm, f'{qmslug=}:{cave_id=} {year=} {qm_id=} {blockname=} {qm.expoyear=} {qm.completion_description=}')
return render(request,'qm.html', {'qm': qm})
else:
- raise
+ #raise
return render(request,'errors/badslug.html', {'badslug': f'{cave_id=} {year=} {qm_id=} {blockname=}'})
except MultipleObjectsReturned:
- raise
+ message = f'Multiple QMs with the same cave, year, number, grade AND first 8 chars of the survexblock name. (Could be caused by incomplete databasereset). Fix this in the survex file(s). {cave_id=} {year=} {qm_id=} {blockname=}'
+ return render(request,'errors/generic.html', {'message': message})
except QM.DoesNotExist:
- raise
+ #raise
return render(request,'errors/badslug.html', {'badslug': f'{cave_id=} {year=} {qm_id=} {blockname=}'})
diff --git a/parsers/QMs.py b/parsers/QMs.py
index 2aa9bbf..484499a 100644
--- a/parsers/QMs.py
+++ b/parsers/QMs.py
@@ -9,14 +9,16 @@ from troggle.core.models.troggle import DataIssue
from troggle.core.models.caves import QM, Cave, LogbookEntry
from troggle.core.utils import save_carefully
-'''Reads the CSV files containg QMs for a select few caves'''
+'''Reads the CSV files containg QMs for a select few caves
+See parsers/survex.py for the parser which extracts QMs from the survex files
+'''
def deleteQMs():
QM.objects.all().delete()
DataIssue.objects.filter(parser='QMs').delete()
-def parseCaveQMs(cave,inputFile):
+def parseCaveQMs(cave, inputFile, ticked=False):
"""Runs through the CSV file at inputFile (which is a relative path from expoweb) and
saves each QM as a QM instance.
This is creating and linking a Placeholder logbookentry dated 1st Jan. in the relevant
@@ -59,7 +61,7 @@ def parseCaveQMs(cave,inputFile):
message = f' ! - {qmPath} KH is not in the database. Please run cave parser'
print(message)
DataIssue.objects.create(parser='QMs', message=message)
- nqms = parse_KH_QMs(kh, inputFile=inputFile)
+ nqms = parse_KH_QMs(kh, inputFile=inputFile, ticked=ticked)
return nqms
#qmPath = settings.EXPOWEB+inputFile
@@ -77,16 +79,6 @@ def parseCaveQMs(cave,inputFile):
n += 1
year=int(line[0][1:5])
logslug = f'PH_{int(year)}_{int(n):02d}'
- # logbook placeholder code was previously here. No longer needed.
- #check if placeholder exists for given year, create it if not
- # message = " ! - "+ str(year) + " logbook: placeholder entry for '" + cave + "' created. DUMMY EXPEDITION ID. Should be re-attached to the actual trip."
- # if cave=='204-steinBH':
- # placeholder, hadToCreate = LogbookEntry.objects.get_or_create(date__year=year, place="204", title="placeholder for QMs in 204", text=message, entry_type="DUMMY", expedition_id=1, defaults={"date": date(year, 1, 1),"cave_slug":str(steinBr), "slug": logslug})
- # elif cave=='234-Hauch':
- # placeholder, hadToCreate = LogbookEntry.objects.get_or_create(date__year=year, place="234", title="placeholder for QMs in 234", text=message, entry_type="DUMMY", expedition_id=1, defaults={"date": date(year, 1, 1),"cave_slug":str(hauchHl)})
- # # if hadToCreate:
- # # print(message)
- # # DataIssue.objects.create(parser='QMs', message=message)
QMnum=re.match(r".*?-\d*?-X?(?P\d*)",line[0]).group("numb")
newQM = QM()
# newQM.found_by=placeholder
@@ -100,12 +92,13 @@ def parseCaveQMs(cave,inputFile):
newQM.area=line[2]
newQM.location_description=line[3]
- # Troggle will in future (?! - written in 2006) check if QMs are completed by checking if they have a ticked_off_by trip.
- # In the table, completion is indicated by the presence of a completion discription.
+ # In the table, completion is indicated by the presence of a completion discription.
newQM.completion_description=line[4]
newQM.nearest_station_description=line[5]
- # if newQM.completion_description:
- # newQM.ticked_off_by=placeholder
+ if newQM.completion_description:
+ newQM.ticked = True
+ else:
+ newQM.ticked = False
newQM.comment=line[6]
try:
@@ -134,7 +127,7 @@ def parseCaveQMs(cave,inputFile):
continue
return nqms
-def parse_KH_QMs(kh, inputFile):
+def parse_KH_QMs(kh, inputFile, ticked):
"""import QMs from the 1623-161 (Kaninchenhohle) html pages, different format
"""
khQMs=open(os.path.join(settings.EXPOWEB, inputFile),'r')
@@ -161,12 +154,13 @@ def parse_KH_QMs(kh, inputFile):
'grade':res['grade']
}
nonLookupArgs={
+ 'ticked': ticked,
'nearest_station_name':res['nearest_station'],
'location_description':res['description']
}
instance, created = save_carefully(QM,lookupArgs,nonLookupArgs)
# if created:
- # message = " ! - "+ instance.code() + " QM entry for '161 KH' created. "
+ # message = f" ! - {instance.code()} QM entry for '161 KH' created. ticked: {ticked}"
# print(message)
# DataIssue.objects.create(parser='QMs', message=message)
nqms += 1
@@ -177,8 +171,9 @@ def Load_QMs():
deleteQMs()
n204 = parseCaveQMs(cave='204-steinBH',inputFile=r"1623/204/qm.csv")
n234 = parseCaveQMs(cave='234-Hauch',inputFile=r"1623/234/qm.csv")
- n161 = parseCaveQMs(cave='161-KH', inputFile="1623/161/qmtodo.htm")
+ n161 = parseCaveQMs(cave='161-KH', inputFile="1623/161/qmtodo.htm", ticked=False)
+ t161 = parseCaveQMs(cave='161-KH', inputFile="1623/161/qmdone.htm", ticked=True)
#parseCaveQMs(cave='balkonhoehle',inputFile=r"1623/264/qm.csv")
- print(f" - Imported: {n204} QMs for 204, {n234} QMs for 234, {n161} QMs for 161.")
+ print(f" - Imported: {n204} QMs for 204, {n234} QMs for 234, {t161} QMs for 161 done, {n161} QMs for 161 not done.")
print ()
diff --git a/parsers/survex.py b/parsers/survex.py
index e1e017a..942dbe9 100644
--- a/parsers/survex.py
+++ b/parsers/survex.py
@@ -545,8 +545,8 @@ class LoadingSurvex():
caveslug = survexblock.survexfile.cave.slug()
place = survexblock.survexfile.cave
else:
- caveslug = "ugh"
- place = "oops"
+ caveslug = None
+ place = None
# message = f' ! - logbook dummy "{logslug}" {str(survexblock.date)[:11]} for cave "{caveslug}" created.'
@@ -568,6 +568,7 @@ class LoadingSurvex():
nearest_station_name=qm_nearest,
grade=qm_grade.upper(),
location_description=qm_notes,
+ block = survexblock, # only set for survex-imported QMs
blockname = blockname, # only set for survex-imported QMs
# found_by = placeholder,
expoyear = str(survexblock.date.year),
diff --git a/templates/cave_qms.html b/templates/cave_qms.html
index c5bde56..358d098 100644
--- a/templates/cave_qms.html
+++ b/templates/cave_qms.html
@@ -7,8 +7,8 @@
Note that QMs loaded for 1623-161, 1623-204 and 1623-234 are imported from CSV files .
QMs are also loaded directly from the survex files, e.g. see
@@ -24,20 +24,29 @@
{% block content %}
Extant
{% if cave.get_QMs %}
-
+
{% for QM in cave.get_QMs %}
- {% if QM.ticked_off_by %}
+ {% if QM.ticked %}
{% else %}
- - {{QM}} :: {{QM.nearest_station_description}} {{QM.location_description}} {{QM.grade}}
+ - {{QM}} :: {{QM.nearest_station_description}} {{QM.location_description}} {{QM.grade}}
+ {% if QM.block %} {{QM.block}}.svx {{QM.block.date}} {% endif %}
{% endif %}
{% endfor %}
Ticked off
{% for QM in cave.get_QMs %}
- {% if QM.ticked_off_by %}
- - {{QM}} :: {{QM.nearest_station_description}} {{QM.location_description}} {{QM.grade}}
+ {% if QM.ticked %}
+ - {{QM}} :: {{QM.nearest_station_description}} {{QM.location_description}} {{QM.grade}}
+ {% if QM.block %} {{QM.block}}.svx {{QM.block.date}} {% endif %}
+
+ {% if QM.completion_description %}
+ Completion page: {{QM.completion_description}}
+ {% endif %}
{% endif %}
+
+
+
{% endfor %}
{% endif %}
diff --git a/templates/qm.html b/templates/qm.html
index 760f010..eb28174 100644
--- a/templates/qm.html
+++ b/templates/qm.html
@@ -4,8 +4,8 @@
{% block contentheader %}
QMs available for these caves from CSV import
QMs are also loaded directly from the survex files, e.g. see
@@ -42,6 +42,11 @@
{{ qm.cave|safe }} cave description
+{% if qm.block %}
+
Survexfile
+{{qm.block.date}} {{qm.block}}.svx
+{% endif %}
+
Location
{{qm.location_description}}
@@ -56,12 +61,12 @@ Found by {{qm.found_by}} on {{qm.
{% endif %}
Completion
-{% if ticked_off_by %}
-{{qm.completion_description}}
-Ticked off by: {{qm.ticked_off_by}}
-Description: {{qm.completion_description}}
+{% if qm.ticked %}
+Ticked off log entry: {{qm.ticked_off_by}}
+Ticked off Description Page: {{qm.get_completion_url}}
{% else %}
-None yet- STILL EXTANT.
+No completion description yet- STILL EXTANT.
+
{% endif %}
Comment