+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'
+
+SAFETY_CHOICES = (
+ ('G', 'G'),
+ ('PG', 'PG'),
+ ('PG13', 'PG13'),
+ ('R', 'R'),
+ ('X', '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.CharField(max_length=4, 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
+
+BOULDER_DIFFICULTY_CHOICES = (
+ ('V0', 'V0'),
+ ('V1', 'V1'),
+ ('V2', 'V2'),
+ ('V3', 'V3'),
+ ('V4', 'V4'),
+ ('V5', 'V5'),
+ ('V6', 'V6'),
+ ('V7', 'V7'),
+ ('V8', 'V8'),
+ ('V9', 'V9'),
+ ('V10', 'V10'),
+ ('V11', 'V11'),
+ ('V12', 'V12'),
+ ('V13', 'V13'),
+ ('V14', 'V14'),
+ ('V15', 'V15'),
+ ('V16', 'V16'),
+ ('V17', 'V17'),
+)
+
+class Problem(models.Model):
+ boulder = models.ForeignKey(
+ Boulder,
+ on_delete=models.CASCADE,
+ related_name='problems',
+ )
+ name = models.CharField(max_length=64)
+ difficulty = models.CharField(max_length=3, choices=BOULDER_DIFFICULTY_CHOICES)
+ safety = models.CharField(max_length=4, 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)