dd2493c4bdc66e5d4c5c6ebef1d120ff5dc966b1
[climbing.kerkeslager.com] / src / climbing / models.py
1 from django.contrib.auth.models import User
2 from django.db import models
3
4 from core import utils
5
6 class Area(models.Model):
7     name = models.CharField(max_length=64)
8     notes = models.TextField(blank=True, null=True)
9
10     def __str__(self):
11         return self.name
12
13     @property
14     def sub_areas(self):
15         return utils.merge(
16             self.crags.order_by('name'),
17             self.clusters.order_by('name'),
18             'name',
19         )
20
21 class Crag(models.Model):
22     area = models.ForeignKey(
23         Area,
24         on_delete=models.CASCADE,
25         related_name='crags',
26     )
27     name = models.CharField(max_length=64)
28     notes = models.TextField(blank=True, null=True)
29
30     def __str__(self):
31         return self.name
32
33 class Route(models.Model):
34     area = models.ForeignKey(
35         Crag,
36         on_delete=models.CASCADE,
37         related_name='routes',
38     )
39     name = models.CharField(max_length=64)
40     mountain_project = models.URLField(blank=True, null=True)
41     notes = models.TextField(blank=True, null=True)
42
43     def __str__(self):
44         pitch_count = self.pitches.count()
45
46         if pitch_count == 0:
47             return self.name
48
49         if pitch_count == 1:
50             return '{} {}'.format(self.name, self.difficulty)
51
52         return '{} {} ({} pitches)'.format(
53             self.name,
54             self.difficulty,
55             pitch_count,
56         )
57
58     @property
59     def difficulty(self):
60         diff = None
61         diff_index = -1
62
63         for pitch in self.pitches.all():
64             for index, diff_choice in enumerate(ROUTE_DIFFICULTY_CHOICES):
65                 if pitch.difficulty == diff_choice[0]:
66                     if diff_index < index:
67                         diff = pitch.difficulty
68                         diff_index = index
69                     break
70
71         return diff
72
73 ROUTE_DIFFICULTY_CHOICES = (
74     ('5.0', '5.0'),
75     ('5.1', '5.1'),
76     ('5.2', '5.2'),
77     ('5.3', '5.3'),
78     ('5.4', '5.4'),
79     ('5.5', '5.5'),
80     ('5.6', '5.6'),
81     ('5.6+', '5.6+'),
82     ('5.7', '5.7'),
83     ('5.7+', '5.7+'),
84     ('5.8', '5.8'),
85     ('5.8+', '5.8+'),
86     ('5.9-', '5.9-'),
87     ('5.9', '5.9'),
88     ('5.9+', '5.9+'),
89     ('5.10a', '5.10a'),
90     ('5.10b', '5.10b'),
91     ('5.10c', '5.10c'),
92     ('5.10d', '5.10d'),
93     ('5.11a', '5.11a'),
94     ('5.11b', '5.11b'),
95     ('5.11c', '5.11c'),
96     ('5.11d', '5.11d'),
97     ('5.12a', '5.12a'),
98     ('5.12b', '5.12b'),
99     ('5.12c', '5.12c'),
100     ('5.12d', '5.12d'),
101     ('5.13a', '5.13a'),
102     ('5.13b', '5.13b'),
103     ('5.13c', '5.13c'),
104     ('5.13d', '5.13d'),
105     ('5.14a', '5.14a'),
106     ('5.14b', '5.14b'),
107     ('5.14c', '5.14c'),
108     ('5.14d', '5.14d'),
109     ('5.15a', '5.15a'),
110     ('5.15b', '5.15b'),
111     ('5.15c', '5.15c'),
112     ('5.15d', '5.15d'),
113 )
114
115 SAFETY_CHOICES = (
116     ('G', 'G'),
117     ('PG', 'PG'),
118     ('PG13', 'PG13'),
119     ('R', 'R'),
120     ('X', 'X'),
121 )
122
123 class Pitch(models.Model):
124     route = models.ForeignKey(
125         Route,
126         on_delete=models.CASCADE,
127         related_name='pitches',
128     )
129     name = models.CharField(max_length=64, blank=True, null=True)
130     difficulty = models.CharField(max_length=5, choices=ROUTE_DIFFICULTY_CHOICES)
131     safety = models.CharField(max_length=4, choices=SAFETY_CHOICES)
132     notes = models.TextField(blank=True, null=True)
133
134     class Meta:
135         verbose_name_plural = 'pitches'
136
137     def __str__(self):
138         if self.name:
139             return '{} ({})'.format(self.name, self.difficulty)
140         return 'Pitch ({})'.format(self.difficulty)
141
142 class Cluster(models.Model):
143     area = models.ForeignKey(
144         Area,
145         on_delete=models.CASCADE,
146         related_name='clusters',
147     )
148     name = models.CharField(max_length=64)
149     notes = models.TextField(blank=True, null=True)
150
151     def __str__(self):
152         return self.name
153
154 class Boulder(models.Model):
155     cluster = models.ForeignKey(
156         Cluster,
157         on_delete=models.CASCADE,
158         related_name='boulders',
159     )
160     name = models.CharField(max_length=64)
161     notes = models.TextField(blank=True, null=True)
162
163     def __str__(self):
164         return self.name
165
166 BOULDER_DIFFICULTY_CHOICES = (
167     ('V0', 'V0'),
168     ('V1', 'V1'),
169     ('V2', 'V2'),
170     ('V3', 'V3'),
171     ('V4', 'V4'),
172     ('V5', 'V5'),
173     ('V6', 'V6'),
174     ('V7', 'V7'),
175     ('V8', 'V8'),
176     ('V9', 'V9'),
177     ('V10', 'V10'),
178     ('V11', 'V11'),
179     ('V12', 'V12'),
180     ('V13', 'V13'),
181     ('V14', 'V14'),
182     ('V15', 'V15'),
183     ('V16', 'V16'),
184     ('V17', 'V17'),
185 )
186
187 class Problem(models.Model):
188     boulder = models.ForeignKey(
189         Boulder,
190         on_delete=models.CASCADE,
191         related_name='problems',
192     )
193     name = models.CharField(max_length=64)
194     difficulty = models.CharField(max_length=3, choices=BOULDER_DIFFICULTY_CHOICES)
195     safety = models.CharField(max_length=4, choices=SAFETY_CHOICES)
196     mountain_project = models.URLField(blank=True, null=True)
197     notes = models.TextField(blank=True, null=True)
198
199     def __str__(self):
200         return '{} ({})'.format(self.name, self.difficulty)
201
202 class RouteTodo(models.Model):
203     user = models.ForeignKey(User, on_delete=models.CASCADE)
204     route = models.ForeignKey(Route, on_delete=models.CASCADE)
205
206 class ProblemTodo(models.Model):
207     user = models.ForeignKey(User, on_delete=models.CASCADE)
208     problem = models.ForeignKey(Problem, on_delete=models.CASCADE)
209
210 class RouteTick(models.Model):
211     user = models.ForeignKey(User, on_delete=models.CASCADE)
212     route = models.ForeignKey(Route, on_delete=models.CASCADE)
213     timestamp = models.DateTimeField()
214     notes = models.TextField(blank=True, null=True)
215
216 class ProblemTick(models.Model):
217     user = models.ForeignKey(User, on_delete=models.CASCADE)
218     problem = models.ForeignKey(Problem, on_delete=models.CASCADE)
219     timestamp = models.DateTimeField()
220     notes = models.TextField(blank=True, null=True)