Refactor calculation of route grade
[climbing.kerkeslager.com] / src / climbing / models.py
index 8be6ee9..dc1396a 100644 (file)
@@ -1,5 +1,7 @@
-from django.db import models
 from django.contrib.auth.models import User
+from django.db import models
+
+from core import utils
 
 class Area(models.Model):
     name = models.CharField(max_length=64)
@@ -10,46 +12,11 @@ class Area(models.Model):
 
     @property
     def sub_areas(self):
-        crags = iter(self.crags.order_by('name'))
-        clusters = iter(self.clusters.order_by('name'))
-
-        try:
-            crag = next(crags)
-        except StopIteration:
-            crag = None
-
-        try:
-            cluster = next(clusters)
-        except StopIteration:
-            cluster = None
-
-        while crag and cluster:
-            if crag.name < cluster.name:
-                yield crag
-                try:
-                    crag = next(crags)
-                except:
-                    crag = None
-            else:
-                yield cluster
-                try:
-                    cluster = next(clusters)
-                except:
-                    cluster = None
-
-        while crag:
-            yield crag
-            try:
-                crag = next(crags)
-            except:
-                crag = None
-
-        while cluster:
-            yield cluster
-            try:
-                cluster = next(clusters)
-            except:
-                cluster = None
+        return utils.merge(
+            self.crags.order_by('name'),
+            self.clusters.order_by('name'),
+            'name',
+        )
 
 class Crag(models.Model):
     area = models.ForeignKey(
@@ -70,10 +37,37 @@ class Route(models.Model):
         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):
-        return self.name
+        pitch_count = self.pitches.count()
+
+        if pitch_count == 0:
+            return self.name
+
+        if pitch_count == 1:
+            return '{} {}'.format(self.name, self.difficulty)
+
+        return '{} {} ({} pitches)'.format(
+            self.name,
+            self.difficulty,
+            pitch_count,
+        )
+
+    @property
+    def difficulty(self):
+        diff = None
+        diff_index = -1
+
+        for pitch in self.pitches.all():
+            p_diff_index = _route_difficulty_index(pitch.difficulty)
+
+            if p_diff_index > diff_index:
+                diff_index = p_diff_index
+                diff = pitch.difficulty
+
+        return diff
 
 ROUTE_DIFFICULTY_CHOICES = (
     ('5.0', '5.0'),
@@ -117,6 +111,12 @@ ROUTE_DIFFICULTY_CHOICES = (
     ('5.15d', '5.15d'),
 )
 
+def _route_difficulty_index(difficulty):
+    for i, d in enumerate(ROUTE_DIFFICULTY_CHOICES):
+        if difficulty == d[0]:
+            return i
+    return -1
+
 SAFETY_CHOICES = (
     ('G', 'G'),
     ('PG', 'PG'),
@@ -131,11 +131,14 @@ class Pitch(models.Model):
         on_delete=models.CASCADE,
         related_name='pitches',
     )
-    name = models.CharField(max_length=64, null=True)
+    name = models.CharField(max_length=64, blank=True, null=True)
     difficulty = models.CharField(max_length=5, choices=ROUTE_DIFFICULTY_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)
@@ -195,6 +198,7 @@ class Problem(models.Model):
     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):