From 3742e0f3670bfe19c6bccce81a4ef9bb11953067 Mon Sep 17 00:00:00 2001
From: Philip Sargent
Date: Mon, 30 Jan 2023 15:28:11 +0000
Subject: [PATCH] fixing Sunday display on calendar
---
core/models/logbooks.py | 15 +++++---
core/models/survex.py | 7 ++--
core/models/troggle.py | 50 ++++++--------------------
core/views/logbooks.py | 74 ++++++++++++++++++++++++---------------
media/css/trog3.css | 7 ++++
parsers/survex.py | 4 ++-
templates/expedition.html | 28 ++++++++-------
7 files changed, 97 insertions(+), 88 deletions(-)
diff --git a/core/models/logbooks.py b/core/models/logbooks.py
index 521eb49..680036a 100644
--- a/core/models/logbooks.py
+++ b/core/models/logbooks.py
@@ -33,6 +33,7 @@ todo='''
'''
class CaveSlug(models.Model):
+ """Moved here to avoid nasty cyclic import error"""
cave = models.ForeignKey('Cave',on_delete=models.CASCADE)
slug = models.SlugField(max_length=50, unique = True)
primary = models.BooleanField(default=False)
@@ -41,7 +42,6 @@ class LogbookEntry(TroggleModel):
"""Single parsed entry from Logbook
"""
date = models.DateField()#MJG wants to turn this into a datetime such that multiple Logbook entries on the same day can be ordered.ld()
- # expeditionday = models.ForeignKey("ExpeditionDay", null=True,on_delete=models.SET_NULL)#MJG wants to KILL THIS (redundant information)
expedition = models.ForeignKey(Expedition,blank=True, null=True,on_delete=models.SET_NULL) # yes this is double-
title = models.CharField(max_length=200)
cave_slug = models.SlugField(max_length=50, blank=True, null=True)
@@ -77,9 +77,16 @@ class LogbookEntry(TroggleModel):
def DayIndex(self):
"""This is used to set different colours for the different trips on
the calendar view of the expedition"""
- index = list(LogbookEntry.objects.filter(date=self.date)).index(self)
- if index not in range(0,10):
- print(f"Unexpected LogbookEntry DayIndex '{index}' {self}")
+ mx = 10
+ todays = list(LogbookEntry.objects.filter(date=self.date))
+ if self in todays:
+ index = todays.index(self)
+ else:
+ print(f"DayIndex: Synchronization error. Restart server. {self}")
+ index = 0
+
+ if index not in range(0, mx):
+ print(f"DayIndex: More than {mx-1} LogbookEntry items on one day '{index}' {self}")
index = 0
return index
diff --git a/core/models/survex.py b/core/models/survex.py
index 4e852f5..24b679a 100644
--- a/core/models/survex.py
+++ b/core/models/survex.py
@@ -148,10 +148,11 @@ class SurvexBlock(models.Model):
def DayIndex(self):
"""This is used to set different colours for the different trips on
the calendar view of the expedition"""
+ mx = 10
index = list(SurvexBlock.objects.filter(date=self.date)).index(self)
- if index not in range(0,10):
- print(f"Unexpected SurvexBlock DayIndex '{index}' {self}")
- index = 10
+ if index not in range(0, mx):
+ print(f"DayIndex: More than {mx-1} SurvexBlock items on one day '{index}' {self}")
+ index = 0
#return list(self.survexblock_set.all()).index(self)
return index
diff --git a/core/models/troggle.py b/core/models/troggle.py
index 4651955..6e470b3 100644
--- a/core/models/troggle.py
+++ b/core/models/troggle.py
@@ -51,6 +51,8 @@ class DataIssue(TroggleModel):
We have replaced all assertions in the code with messages and local fix-ups or skips:
https://martinfowler.com/articles/replaceThrowWithNotification.html
+
+ See also the use of stash_data_issue() & store_data_issues() in parsers/survex.py which defer writing to the database until the end of the import.
"""
date = models.DateTimeField(auto_now_add=True, blank=True)
parser = models.CharField(max_length=50, blank=True, null=True)
@@ -81,34 +83,9 @@ class Expedition(TroggleModel):
def get_absolute_url(self):
return urljoin(settings.URL_ROOT, reverse('expedition', args=[self.year]))
- # construction function. should be moved out
- # def get_expedition_day(self, date):
- # expeditiondays = self.expeditionday_set.filter(date=date)
- # if expeditiondays:
- # if len(expeditiondays) == 1:
- # return expeditiondays[0]
- # else:
- # message =f'! - More than one expeditionday for the same date: {date} .\n - This should never happen. \n - Restart mysql and run reset to clean database.'
- # DataIssue.objects.create(parser='expedition', message=message)
- # return expeditiondays[0]
- # res = ExpeditionDay(expedition=self, date=date)
- # res.save()
- # return res
-
- # def day_min(self):
- # """First day of expedition
- # """
- # res = self.expeditionday_set.all()
- # return res and res[0] or None
-
- # def day_max(self):
- # """last day of expedition
- # """
- # res = self.expeditionday_set.all()
- # return res and res[len(res) - 1] or None
class ExpeditionDay(TroggleModel):
- """Exists only on Expedition now. Removed from logbookentry, persontrip, survex stuff etc.
+ """Exists only on Expedition now. Removed links from logbookentry, persontrip, survex stuff etc.
"""
expedition = models.ForeignKey("Expedition",on_delete=models.CASCADE)
date = models.DateField()
@@ -116,11 +93,11 @@ class ExpeditionDay(TroggleModel):
class Meta:
ordering = ('date',)
- def GetPersonTrip(self, personexpedition):
- """returns all logbook trips for this expeditonday
- """
- personexpeditions = self.persontrip_set.filter(expeditionday=self)
- return personexpeditions and personexpeditions[0] or None
+ # def GetPersonTrip(self, personexpedition):
+ # """returns all logbook trips for this expeditonday
+ # """
+ # personexpeditions = self.persontrip_set.filter(expeditionday=self)
+ # return personexpeditions and personexpeditions[0] or None
class Person(TroggleModel):
"""single Person, can go on many years
@@ -182,7 +159,7 @@ class PersonExpedition(TroggleModel):
slugfield = models.SlugField(max_length=50,blank=True, null=True) # 2022 to be used in future
is_guest = models.BooleanField(default=False)
- nickname = models.CharField(max_length=100,blank=True, null=True)
+ nickname = models.CharField(max_length=100,blank=True, null=True) # removbe this
class Meta:
ordering = ('-expedition',)
@@ -208,11 +185,4 @@ class PersonExpedition(TroggleModel):
survexblocks = [personrole.survexblock for personrole in self.survexpersonrole_set.all() ]
return sum([survexblock.legslength for survexblock in set(survexblocks)])
- # would prefer to return actual person trips so we could link to first and last ones
- # def day_min(self):
- # res = self.persontrip_set.aggregate(day_min=Min("expeditionday__date"))
- # return res["day_min"]
-
- # def day_max(self):
- # res = self.persontrip_set.all().aggregate(day_max=models.Max("expeditionday__date"))
- # return res["day_max"]
+
\ No newline at end of file
diff --git a/core/views/logbooks.py b/core/views/logbooks.py
index 2cfc183..5ffae6a 100644
--- a/core/views/logbooks.py
+++ b/core/views/logbooks.py
@@ -58,22 +58,32 @@ def notablepersons(request):
def expedition(request, expeditionname):
'''Returns a rendered page for one expedition, specified by the year e.g. '2019'.
If page caching is enabled, it caches the dictionaries used to render the template page.
+
+ This is not as difficult to understand as it looks. Yes there are many levels of indirection, with multiple trees being traversed at the same time. And the Django special syntax
+ makes this hard for normal Python programmers.
+
+ Remember that 'personexpedition__expedition' is interpreted by Django to mean the
+ 'expedition' object which is connected by a foreign key to the 'personexpedition'
+ object, which is a field of the PersonTrip object:
+ PersonTrip.objects.filter(personexpedition__expedition=expo)
+
+ Queries are not evaluated to hit the database until a result is actually used. Django
+ does lazy evaluation.
+
'''
+ try:
+ expo = Expedition.objects.get(year=int(expeditionname))
+ except:
+ message = f'Expedition not found - database apparently empty, you probably need to do a full re-import of all data.'
+ return render(request, 'errors/generic.html', {'message': message})
+
if request.user.is_authenticated:
- if "reload" in request.GET:
- this_expedition = Expedition.objects.get(year=int(expeditionname))
- # Need to delete the existing entries or we get duplication
- # Need to delete both in the Django ORM and in our own object-store.
- entries = this_expedition.logbookentry_set.all()
- for entry in entries:
- #print(f'! - delete entry: "{entry}"')
- entry.delete()
- entries = this_expedition.logbookentry_set.all()
- import_logbook(year=this_expedition.year)
logged_in = True
+ if "reload" in request.GET:
+ expo.logbookentry_set.all().delete()
+ import_logbook(year=expo.year)
else:
logged_in = False
-
ts = TROG['pagecache']['expedition'] # not much use unless single user!
if settings.CACHEDPAGES:
@@ -83,33 +93,41 @@ def expedition(request, expeditionname):
#print('! - expo {expeditionanme} using cached page')
return render(request,'expedition.html', { **ts[expeditionname], 'logged_in' : logged_in })
- try:
- this_expedition = Expedition.objects.get(year=int(expeditionname))
- except:
- message = f'Expedition not found - database apparently empty, you probably need to do a full re-import of all data.'
- return render(request, 'errors/generic.html', {'message': message})
-
- expeditions = Expedition.objects.all()
- personexpeditiondays = [ ]
- dateditems = list(this_expedition.logbookentry_set.all()) + list(this_expedition.survexblock_set.all())
+ expeditions = Expedition.objects.all() # top menu only, evaluated only when template renders
+
+ entries = expo.logbookentry_set.all()
+ blocks = expo.survexblock_set.all()
+ dateditems = list(entries) + list(blocks) # evaluates the Django query and hits db
dates = sorted(set([item.date for item in dateditems]))
- for personexpedition in this_expedition.personexpedition_set.all():
+
+ allpersontrips = PersonTrip.objects.filter(personexpedition__expedition=expo)
+
+
+ personexpeditiondays = [ ]
+ for personexpedition in expo.personexpedition_set.all():
+ expotrips = allpersontrips.filter(personexpedition=personexpedition) # lazy
+ expoblocks = blocks.filter(survexpersonrole__personexpedition=personexpedition)
+
prow = [ ]
+
for date in dates:
- pcell = { "persontrips": PersonTrip.objects.filter(personexpedition=personexpedition,
- logbook_entry__date=date) }
- pcell["survexblocks"] = set(SurvexBlock.objects.filter(survexpersonrole__personexpedition=personexpedition,
- date = date))
+ personentries = expotrips.filter(logbook_entry__date=date) # lazy
+ personblocks = set(expoblocks.filter(date = date)) # not lazy
+ pcell = {}
+ pcell["personentries"] = personentries
+ pcell["survexblocks"] = personblocks
+ if issunday := (date.weekday() == 6): # WALRUS
+ pcell["sunday"] = issunday
prow.append(pcell)
personexpeditiondays.append({"personexpedition":personexpedition, "personrow":prow})
- ts[expeditionname] = {'expedition': this_expedition, 'expeditions':expeditions,
+ ts[expeditionname] = {'expedition': expo,
+ 'expeditions':expeditions,
'personexpeditiondays':personexpeditiondays, 'settings':settings,
'dateditems': dateditems, 'dates':dates}
TROG['pagecache']['expedition'][expeditionname] = ts[expeditionname]
- nexpos = len( TROG['pagecache']['expedition'])
- #print(f'! - expo {expeditionname} pre-render N expos:{nexpos}')
+
return render(request,'expedition.html', { **ts[expeditionname], 'logged_in' : logged_in } )
class Expeditions_tsvListView(ListView):
diff --git a/media/css/trog3.css b/media/css/trog3.css
index e0097b9..48fbd95 100644
--- a/media/css/trog3.css
+++ b/media/css/trog3.css
@@ -55,12 +55,19 @@ table.expeditionpersonlist td.persondayactivity
width:4em;
font-size:70%;
padding:0 0 0 0;
+ background-color:#ddd;
}
+
table.expeditionpersonlist td.persondayactivity-nothing
{
background-color:#bbb;
}
+table.expeditionpersonlist td.persondayactivity-sunday
+{
+ background-color:#aad;
+}
+
table.expeditionpersonlist a
{
text-decoration:none;
diff --git a/parsers/survex.py b/parsers/survex.py
index 634aeca..4861817 100644
--- a/parsers/survex.py
+++ b/parsers/survex.py
@@ -60,7 +60,9 @@ def stash_data_issue(parser=None, message=None, url=None, sb=None):
dataissues.append((parser, message, url, sb))
def store_data_issues():
- """Take the stash and store it permanently in the database instead"""
+ """Take the stash and store it permanently in the database instead
+
+ use BULK creation here !"""
global dataissues
print(f" - Storing {len(dataissues)} Data Issues into database")
diff --git a/templates/expedition.html b/templates/expedition.html
index 0188107..eda8fde 100644
--- a/templates/expedition.html
+++ b/templates/expedition.html
@@ -27,10 +27,10 @@
{% endif %}
At a single glance: The table shows all expo cavers and their recorded trips.
-The columns are the date in the month (July or August), with a
+The columns are the date in the month (July, August or September), Sundays in blue, with a
"T" for a logbook entry, and
-an "S" for a survey trip. The colours are the same for people on the same trip.
-
+an "S" for a survey trip. The colours of the "T" and "S" are the same for people on the same trip.
+
@@ -44,21 +44,25 @@ an "S" for a survey trip. The colours are the same for people on the sam
{% for personexpeditionday in personexpeditiondays %}
{{personexpeditionday.personexpedition.person|safe}} |
- {% for persondayactivities in personexpeditionday.personrow %}
+ {% for activities in personexpeditionday.personrow %}
- {% if persondayactivities.persontrips or persondayactivities.survexblocks %}
-
- {% for persontrip in persondayactivities.persontrips %}
- T
+ {% if activities.personentries or activities.survexblocks %}
+ |
+ {% for personentry in activities.personentries %}
+ T
{% endfor %}
-
- {% for survexblock in persondayactivities.survexblocks %}
+
+ {% for survexblock in activities.survexblocks %}
S
{% endfor %}
|
{% else %}
-
- |
+ {% if activities.sunday %}
+
+ {% else %}
+ |
+ {% endif %}
+ |
{% endif %}
{% endfor %}