From 94e145adcea17d7a220f459d201c824bfb7ff42d Mon Sep 17 00:00:00 2001 From: Philip Sargent Date: Mon, 6 Mar 2023 16:37:38 +0000 Subject: [PATCH] CASCADE fixes in data model --- core/models/caves.py | 5 +++++ core/models/logbooks.py | 12 ++++++++--- core/models/survex.py | 48 ++++++++++++++++++++++++++--------------- core/models/troggle.py | 10 +++++---- parsers/locations.py | 5 +++++ 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/core/models/caves.py b/core/models/caves.py index 1de5ef9..6492698 100644 --- a/core/models/caves.py +++ b/core/models/caves.py @@ -59,6 +59,9 @@ class Area(TroggleModel): class CaveAndEntrance(models.Model): + """CASCADE means that if the cave or the entrance is deleted, then this CaveAndEntrance + is deleted too + """ cave = models.ForeignKey("Cave", on_delete=models.CASCADE) entrance = models.ForeignKey("Entrance", on_delete=models.CASCADE) entrance_letter = models.CharField(max_length=20, blank=True, null=True) @@ -240,6 +243,8 @@ class Cave(TroggleModel): class EntranceSlug(models.Model): + """If the Entrance is deleted, then this EntranceSlug is deleted too + """ entrance = models.ForeignKey("Entrance", on_delete=models.CASCADE) slug = models.SlugField(max_length=50, unique=True) primary = models.BooleanField(default=False) diff --git a/core/models/logbooks.py b/core/models/logbooks.py index 89abca4..4932a57 100644 --- a/core/models/logbooks.py +++ b/core/models/logbooks.py @@ -17,7 +17,9 @@ todo = """ class CaveSlug(models.Model): - """Moved here to avoid nasty cyclic import error""" + """Moved here to avoid nasty cyclic import error + CASCADE means that if the Cave is deleted, this is too + """ cave = models.ForeignKey("Cave", on_delete=models.CASCADE) slug = models.SlugField(max_length=50, unique=True) @@ -25,12 +27,13 @@ class CaveSlug(models.Model): class LogbookEntry(TroggleModel): - """Single parsed entry from Logbook""" + """Single parsed entry from Logbook + Gets deleted if the Expedition gets deleted""" date = ( models.DateField() ) # MJG wants to turn this into a datetime such that multiple Logbook entries on the same day can be ordered.ld() - expedition = models.ForeignKey(Expedition, blank=True, null=True, on_delete=models.SET_NULL) # yes this is double- + expedition = models.ForeignKey(Expedition, blank=True, null=True, on_delete=models.CASCADE) # yes this is double- title = models.CharField(max_length=200) cave_slug = models.SlugField(max_length=50, blank=True, null=True) place = models.CharField( @@ -84,6 +87,9 @@ class LogbookEntry(TroggleModel): class PersonLogEntry(TroggleModel): """Single Person going on a trip, which may or may not be written up. It could account for different T/U for people in same logbook entry. + + CASCADE means that if the personexpedition or the logbookentry is deleted, + then this PersonLogEntry is deleted too """ personexpedition = models.ForeignKey("PersonExpedition", null=True, on_delete=models.CASCADE) diff --git a/core/models/survex.py b/core/models/survex.py index c1d8ca2..b82bd90 100644 --- a/core/models/survex.py +++ b/core/models/survex.py @@ -12,7 +12,11 @@ from django.urls import reverse class SurvexDirectory(models.Model): - path = models.CharField(max_length=200) + """This relates a Cave to the primary SurvexFile which is the 'head' of the survex tree for + that cave. Surely this could just be a property of Cave ? No. Several subdirectories + all relate to the same Cave + """ + path = models.CharField(max_length=200) cave = models.ForeignKey("Cave", blank=True, null=True, on_delete=models.SET_NULL) primarysurvexfile = models.ForeignKey( "SurvexFile", related_name="primarysurvexfile", blank=True, null=True, on_delete=models.SET_NULL @@ -66,7 +70,10 @@ class SurvexFile(models.Model): class SurvexStationLookUpManager(models.Manager): """Don't know what this does, - https://docs.djangoproject.com/en/dev/topics/db/managers/""" + https://docs.djangoproject.com/en/dev/topics/db/managers/ + This changes the .objects thinggy to use a case-insensitive match name__iexact + so that now SurvexStation.objects.lookup() works as a case-insensitive match + """ def lookup(self, name): blocknames, sep, stationname = name.rpartition(".") return self.get(block=SurvexBlock.objects.lookup(blocknames), name__iexact=stationname) @@ -75,7 +82,7 @@ class SurvexStationLookUpManager(models.Manager): class SurvexStation(models.Model): name = models.CharField(max_length=100) block = models.ForeignKey("SurvexBlock", null=True, on_delete=models.SET_NULL) - objects = SurvexStationLookUpManager() + objects = SurvexStationLookUpManager() # overwrites SurvexStation.objects x = models.FloatField(blank=True, null=True) y = models.FloatField(blank=True, null=True) z = models.FloatField(blank=True, null=True) @@ -101,18 +108,22 @@ class SurvexStation(models.Model): # # Single SurvexBlock # -class SurvexBlockLookUpManager(models.Manager): - """Don't know what this does, - https://docs.djangoproject.com/en/dev/topics/db/managers/ """ - def lookup(self, name): - if name == "": - blocknames = [] - else: - blocknames = name.split(".") - block = SurvexBlock.objects.get(parent=None, survexfile__path=settings.SURVEX_TOPNAME) - for blockname in blocknames: - block = SurvexBlock.objects.get(parent=block, name__iexact=blockname) - return block +# class SurvexBlockLookUpManager(models.Manager): + # """Don't know what this does, + # https://docs.djangoproject.com/en/dev/topics/db/managers/ + + # This changes the .objects_set thinggy to use a case-insensitive match name__iexact + # so that now SurvexBlock.objects.lookup() works as a case-insensitive match UNUSED + # """ + # def lookup(self, name): + # if name == "": + # blocknames = [] + # else: + # blocknames = name.split(".") + # # block = SurvexBlock.objects.get(parent=None, survexfile__path=settings.SURVEX_TOPNAME) + # for blockname in blocknames: + # block = SurvexBlock.objects.get(parent=block, name__iexact=blockname) + # return block class SurvexBlock(models.Model): @@ -120,7 +131,7 @@ class SurvexBlock(models.Model): Multiple anonymous survex blocks are possible within the same surfex file """ - objects = SurvexBlockLookUpManager() + # objects = SurvexBlockLookUpManager() name = models.CharField(max_length=100) title = models.CharField(max_length=200) parent = models.ForeignKey("SurvexBlock", blank=True, null=True, on_delete=models.SET_NULL) @@ -163,10 +174,13 @@ class SurvexBlock(models.Model): class SurvexPersonRole(models.Model): + """The CASCADE means that if a SurvexBlock or a Person is deleted, then the SurvexPersonRole + is deleted too + """ survexblock = models.ForeignKey("SurvexBlock", on_delete=models.CASCADE) # increasing levels of precision, Surely we only need survexblock and person now that we have no link to a logbook entry? personname = models.CharField(max_length=100) - person = models.ForeignKey("Person", blank=True, null=True, on_delete=models.SET_NULL) # not needed + person = models.ForeignKey("Person", blank=True, null=True, on_delete=models.CASCADE) # not needed personexpedition = models.ForeignKey("PersonExpedition", blank=True, null=True, on_delete=models.SET_NULL) def __str__(self): diff --git a/core/models/troggle.py b/core/models/troggle.py index ee66b64..1ca7a9a 100644 --- a/core/models/troggle.py +++ b/core/models/troggle.py @@ -11,7 +11,7 @@ import settings """This file declares TroggleModel which inherits from django.db.models.Model All TroggleModel and models.Model subclasses inherit persistence in the django relational database. This is known as the django Object Relational Mapping (ORM). -There are more subclasses define in models_caves.py models_survex.py etc. +There are more subclasses defined in models/caves.py models/survex.py etc. """ @@ -33,7 +33,7 @@ class TroggleModel(models.Model): class DataIssue(TroggleModel): """When importing cave data any validation problems produce a message which is - recorded as a DataIssue. The django admin system automatically prodiuces a page listing + recorded as a DataIssue. The django admin system automatically produces a page listing these at /admin/core/dataissue/ This is a use of the NOTIFICATION pattern: https://martinfowler.com/eaaDev/Notification.html @@ -55,7 +55,6 @@ class DataIssue(TroggleModel): def __str__(self): return f"{self.parser} - {self.message}" - # # single Expedition, usually seen by year # @@ -150,7 +149,10 @@ class Person(TroggleModel): class PersonExpedition(TroggleModel): - """Person's attendance to one Expo""" + """Person's attendance to one Expo + CASCADE means that if an expedition or a person is deleted, the PersonExpedition + is deleted too + """ expedition = models.ForeignKey(Expedition, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) diff --git a/parsers/locations.py b/parsers/locations.py index fbed49b..8384028 100644 --- a/parsers/locations.py +++ b/parsers/locations.py @@ -212,6 +212,11 @@ def LoadPositions(): # But why are we doing this? Why do we need the survexblock id for each of these ? # ..because mostly they don't actually appear in any SVX file. We should match them up # via the cave data, not by this half-arsed syntactic match which almost never works. PMS. + + # It is pointless linking them all to the root survexblock, they don't need it. + # If there is a link to a survexblock it should be the one the station appears in ! + # But we are reading the .pos file so we only know the SurvexFile not the SurvexBlock.. + # ghastly. if False: try: sbqs = SurvexBlock.objects.filter(survexpath=blockpath)