diff options
author | Philip Sargent <philip.sargent@klebos.com> | 2021-04-13 00:43:57 +0100 |
---|---|---|
committer | Philip Sargent <philip.sargent@klebos.com> | 2021-04-13 00:43:57 +0100 |
commit | 5b3b0e67e9744671fadeca78e5565d3dbd1f81c1 (patch) | |
tree | 0b6b9e52d023567bc1e92878ce43a0b7b2fada26 /core/models/troggle.py | |
parent | 304bbd230a1b801069cfce259c6ad0f25d48116c (diff) | |
download | troggle-5b3b0e67e9744671fadeca78e5565d3dbd1f81c1.tar.gz troggle-5b3b0e67e9744671fadeca78e5565d3dbd1f81c1.tar.bz2 troggle-5b3b0e67e9744671fadeca78e5565d3dbd1f81c1.zip |
create core/models/ directroy
Diffstat (limited to 'core/models/troggle.py')
-rw-r--r-- | core/models/troggle.py | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/core/models/troggle.py b/core/models/troggle.py new file mode 100644 index 0000000..760c94f --- /dev/null +++ b/core/models/troggle.py @@ -0,0 +1,225 @@ +import string +import os +import datetime +import logging +import re +import resource +from subprocess import call + +from urllib.parse import urljoin +from decimal import Decimal, getcontext +getcontext().prec=2 #use 2 significant figures for decimal calculations + +import settings + +from django.db import models +from django.contrib import admin +from django.contrib.auth.models import User +from django.contrib.contenttypes.models import ContentType +from django.conf import settings + +from django.urls import reverse +from django.template import Context, loader + +import troggle.core.models_survex +from troggle.core.utils import get_process_memory + +"""This file declares TroggleModel which inherits from django.db.models.Model +All TroggleModel 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. +""" + + +#This class is for adding fields and methods which all of our models will have. +class TroggleModel(models.Model): + new_since_parsing = models.BooleanField(default=False, editable=False) + non_public = models.BooleanField(default=False) + def object_name(self): + return self._meta.object_name + + def get_admin_url(self): + return urljoin(settings.URL_ROOT, "/admin/core/" + self.object_name().lower() + "/" + str(self.pk)) + + class Meta: + abstract = True + +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 + these at /admin/core/dataissue/ + This is a use of the NOTIFICATION pattern: + https://martinfowler.com/eaaDev/Notification.html + + And we need to use it to replace all assertions in the code too: + https://martinfowler.com/articles/replaceThrowWithNotification.html + """ + date = models.DateTimeField(auto_now_add=True, blank=True) + parser = models.CharField(max_length=50, blank=True, null=True) + message = models.CharField(max_length=400, blank=True, null=True) + url = models.CharField(max_length=300, blank=True, null=True) # link to offending object + + class Meta: + ordering = ['date'] + + def __str__(self): + return "%s - %s" % (self.parser, self.message) + +# +# single Expedition, usually seen by year +# +class Expedition(TroggleModel): + year = models.CharField(max_length=20, unique=True) + name = models.CharField(max_length=100) + + def __str__(self): + return self.year + + class Meta: + ordering = ('-year',) + get_latest_by = 'year' + + 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 ='! - more than one datum in an expeditionday: {}'.format(date) + DataIssue.objects.create(parser='expedition', message=message) + return expeditiondays[0] + res = ExpeditionDay(expedition=self, date=date) + res.save() + return res + + def day_min(self): + res = self.expeditionday_set.all() + return res and res[0] or None + + def day_max(self): + res = self.expeditionday_set.all() + return res and res[len(res) - 1] or None + +class ExpeditionDay(TroggleModel): + expedition = models.ForeignKey("Expedition",on_delete=models.CASCADE) + date = models.DateField() + + class Meta: + ordering = ('date',) + + def GetPersonTrip(self, personexpedition): + personexpeditions = self.persontrip_set.filter(expeditionday=self) + return personexpeditions and personexpeditions[0] or None + +class Person(TroggleModel): + """single Person, can go on many years + """ + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + fullname = models.CharField(max_length=200) + is_vfho = models.BooleanField(help_text="VFHO is the Vereines für Höhlenkunde in Obersteier, a nearby Austrian caving club.", default=False) + mug_shot = models.CharField(max_length=100, blank=True,null=True) + blurb = models.TextField(blank=True,null=True) + + #href = models.CharField(max_length=200) + orderref = models.CharField(max_length=200) # for alphabetic + user = models.OneToOneField(User, null=True, blank=True,on_delete=models.CASCADE) + def get_absolute_url(self): + return urljoin(settings.URL_ROOT,reverse('person',kwargs={'first_name':self.first_name,'last_name':self.last_name})) + + class Meta: + verbose_name_plural = "People" + ordering = ('orderref',) # "Wookey" makes too complex for: ('last_name', 'first_name') + + def __str__(self): + if self.last_name: + return "%s %s" % (self.first_name, self.last_name) + return self.first_name + + + def notability(self): + notability = Decimal(0) + max_expo_val = 0 + + max_expo_year = Expedition.objects.all().aggregate(models.Max('year')) + max_expo_val = int(max_expo_year['year__max']) + 1 + + for personexpedition in self.personexpedition_set.all(): + if not personexpedition.is_guest: + notability += Decimal(1) / (max_expo_val - int(personexpedition.expedition.year)) + return notability + + def bisnotable(self): + return self.notability() > Decimal(1)/Decimal(3) + + def surveyedleglength(self): + return sum([personexpedition.surveyedleglength() for personexpedition in self.personexpedition_set.all()]) + + def first(self): + return self.personexpedition_set.order_by('-expedition')[0] + def last(self): + return self.personexpedition_set.order_by('expedition')[0] + +class PersonExpedition(TroggleModel): + """Person's attendance to one Expo + """ + expedition = models.ForeignKey(Expedition,on_delete=models.CASCADE) + person = models.ForeignKey(Person,on_delete=models.CASCADE) + slugfield = models.SlugField(max_length=50,blank=True, null=True) + + is_guest = models.BooleanField(default=False) + COMMITTEE_CHOICES = ( + ('leader','Expo leader'), + ('medical','Expo medical officer'), + ('treasurer','Expo treasurer'), + ('sponsorship','Expo sponsorship coordinator'), + ('research','Expo research coordinator'), + ) + expo_committee_position = models.CharField(blank=True,null=True,choices=COMMITTEE_CHOICES,max_length=200) + nickname = models.CharField(max_length=100,blank=True, null=True) + + def GetPersonroles(self): + res = [ ] + for personrole in self.personrole_set.order_by('survexblock'): + if res and res[-1]['survexpath'] == personrole.survexblock.survexpath: + res[-1]['roles'] += ", " + str(personrole.role) + else: + res.append({'date':personrole.survexblock.date, 'survexpath':personrole.survexblock.survexpath, 'roles':str(personrole.role)}) + return res + + class Meta: + ordering = ('-expedition',) + #order_with_respect_to = 'expedition' + + def __str__(self): + return "%s: (%s)" % (self.person, self.expedition) + + #why is the below a function in personexpedition, rather than in person? - AC 14 Feb 09 + def name(self): + if self.nickname: + return "%s (%s) %s" % (self.person.first_name, self.nickname, self.person.last_name) + if self.person.last_name: + return "%s %s" % (self.person.first_name, self.person.last_name) + return self.person.first_name + + def get_absolute_url(self): + return urljoin(settings.URL_ROOT, reverse('personexpedition',kwargs={'first_name':self.person.first_name,'last_name':self.person.last_name,'year':self.expedition.year})) + + def surveyedleglength(self): + 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"] + + |