X-Git-Url: https://code.kerkeslager.com/?a=blobdiff_plain;f=src%2Fclimbing%2Fmodels.py;h=69bbc9ff6a6ea68ee05b873e699238c5cfc46c03;hb=refs%2Fheads%2Fmain;hp=71a836239075aa6e6e4ecb700e9c42c95c022d91;hpb=a61e6c6f81f4b3b226cdc232272f2cea3a129c2a;p=climbing.kerkeslager.com diff --git a/src/climbing/models.py b/src/climbing/models.py index 71a8362..69bbc9f 100644 --- a/src/climbing/models.py +++ b/src/climbing/models.py @@ -1,3 +1,216 @@ +from django.contrib.auth.models import User from django.db import models -# Create your models here. +from core import utils + +class Area(models.Model): + name = models.CharField(max_length=64) + notes = models.TextField(blank=True, null=True) + + def __str__(self): + return self.name + + @property + def sub_areas(self): + return utils.merge( + self.crags.order_by('name'), + self.clusters.order_by('name'), + 'name', + ) + +class Crag(models.Model): + area = models.ForeignKey( + Area, + on_delete=models.CASCADE, + related_name='crags', + ) + name = models.CharField(max_length=64) + notes = models.TextField(blank=True, null=True) + + def __str__(self): + return self.name + +class Route(models.Model): + area = models.ForeignKey( + Crag, + on_delete=models.CASCADE, + related_name='routes', + ) + name = models.CharField(max_length=64) + mountain_project = models.URLField(blank=True, null=True) + notes = models.TextField(blank=True, null=True) + + def __str__(self): + pitch_count = self.pitches.count() + + if pitch_count == 0: + return self.name + + if pitch_count == 1: + return '{} {}'.format(self.name, self.difficulty_display) + + return '{} {} ({} pitches)'.format( + self.name, + self.difficulty_display, + pitch_count, + ) + + @property + def difficulty(self): + diff = -1 + + for pitch in self.pitches.all(): + diff = max(diff, pitch.difficulty) + + return diff + + @property + def difficulty_display(self): + return RouteDifficulty(self.difficulty).label + +class RouteDifficulty(models.IntegerChoices): + YDS_5_0 = 0, '5.0' + YDS_5_1 = 1, '5.1' + YDS_5_2 = 2, '5.2' + YDS_5_3 = 3, '5.3' + YDS_5_4 = 4, '5.4' + YDS_5_5 = 5, '5.5' + YDS_5_6 = 6, '5.6' + YDS_5_6p = 7, '5.6+' + YDS_5_7 = 8, '5.7' + YDS_5_7p = 9, '5.7+' + YDS_5_8 = 10, '5.8' + YDS_5_8p = 11, '5.8+' + YDS_5_9m = 12, '5.9-' + YDS_5_9 = 13, '5.9' + YDS_5_9p = 14, '5.9+' + YDS_5_10a = 15, '5.10a' + YDS_5_10b = 16, '5.10b' + YDS_5_10c = 17, '5.10c' + YDS_5_10d = 18, '5.10d' + YDS_5_11a = 19, '5.11a' + YDS_5_11b = 20, '5.11b' + YDS_5_11c = 21, '5.11c' + YDS_5_11d = 22, '5.11d' + YDS_5_12a = 23, '5.12a' + YDS_5_12b = 24, '5.12b' + YDS_5_12c = 25, '5.12c' + YDS_5_12d = 26, '5.12d' + YDS_5_13a = 27, '5.13a' + YDS_5_13b = 28, '5.13b' + YDS_5_13c = 29, '5.13c' + YDS_5_13d = 30, '5.13d' + YDS_5_14a = 31, '5.14a' + YDS_5_14b = 32, '5.14b' + YDS_5_14c = 33, '5.14c' + YDS_5_14d = 34, '5.14d' + YDS_5_15a = 35, '5.15a' + YDS_5_15b = 36, '5.15b' + YDS_5_15c = 37, '5.15c' + YDS_5_15d = 38, '5.15d' + +class Safety(models.IntegerChoices): + G = 0, 'G' + PG = 1, 'PG' + PG13 = 2, 'PG13' + R = 3, 'R' + X = 4, 'X' + +class Pitch(models.Model): + route = models.ForeignKey( + Route, + on_delete=models.CASCADE, + related_name='pitches', + ) + name = models.CharField(max_length=64, blank=True, null=True) + difficulty = models.PositiveIntegerField(choices=RouteDifficulty.choices) + safety = models.IntegerField(choices=Safety.choices) + notes = models.TextField(blank=True, null=True) + + class Meta: + verbose_name_plural = 'pitches' + + def __str__(self): + if self.name: + return '{} ({})'.format(self.name, self.difficulty) + return 'Pitch ({})'.format(self.difficulty) + +class Cluster(models.Model): + area = models.ForeignKey( + Area, + on_delete=models.CASCADE, + related_name='clusters', + ) + name = models.CharField(max_length=64) + notes = models.TextField(blank=True, null=True) + + def __str__(self): + return self.name + +class Boulder(models.Model): + cluster = models.ForeignKey( + Cluster, + on_delete=models.CASCADE, + related_name='boulders', + ) + name = models.CharField(max_length=64) + notes = models.TextField(blank=True, null=True) + + def __str__(self): + return self.name + +class BoulderDifficylty(models.IntegerChoices): + V0 = 0, 'V0' + V1 = 1, 'V1' + V2 = 2, 'V2' + V3 = 3, 'V3' + V4 = 4, 'V4' + V5 = 5, 'V5' + V6 = 6, 'V6' + V7 = 7, 'V7' + V8 = 8, 'V8' + V9 = 9, 'V9' + V10 = 10, 'V10' + V11 = 11, 'V11' + V12 = 12, 'V12' + V13 = 13, 'V13' + V14 = 14, 'V14' + V15 = 15, 'V15' + V16 = 16, 'V16' + V17 = 17, 'V17' + + +class Problem(models.Model): + boulder = models.ForeignKey( + Boulder, + on_delete=models.CASCADE, + related_name='problems', + ) + name = models.CharField(max_length=64) + difficulty = models.IntegerField(choices=BoulderDifficylty.choices) + safety = models.IntegerField(choices=Safety.choices) + mountain_project = models.URLField(blank=True, null=True) + notes = models.TextField(blank=True, null=True) + + def __str__(self): + return '{} ({})'.format(self.name, self.difficulty) + +class RouteTodo(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + route = models.ForeignKey(Route, on_delete=models.CASCADE) + +class ProblemTodo(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + problem = models.ForeignKey(Problem, on_delete=models.CASCADE) + +class RouteTick(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + route = models.ForeignKey(Route, on_delete=models.CASCADE) + timestamp = models.DateTimeField() + notes = models.TextField(blank=True, null=True) + +class ProblemTick(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + problem = models.ForeignKey(Problem, on_delete=models.CASCADE) + timestamp = models.DateTimeField() + notes = models.TextField(blank=True, null=True)