Shift over rest of choices to IntegerChoices
[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_display)
51
52         return '{} {} ({} pitches)'.format(
53             self.name,
54             self.difficulty_display,
55             pitch_count,
56         )
57
58     @property
59     def difficulty(self):
60         diff = -1
61
62         for pitch in self.pitches.all():
63             diff = max(diff, pitch.difficulty)
64
65         return diff
66
67     @property
68     def difficulty_display(self):
69         return RouteDifficulty(self.difficulty).label
70
71 class RouteDifficulty(models.IntegerChoices):
72     YDS_5_0 = 0, '5.0'
73     YDS_5_1 = 1, '5.1'
74     YDS_5_2 = 2, '5.2'
75     YDS_5_3 = 3, '5.3'
76     YDS_5_4 = 4, '5.4'
77     YDS_5_5 = 5, '5.5'
78     YDS_5_6 = 6, '5.6'
79     YDS_5_6p = 7, '5.6+'
80     YDS_5_7 = 8, '5.7'
81     YDS_5_7p = 9, '5.7+'
82     YDS_5_8 = 10, '5.8'
83     YDS_5_8p = 11, '5.8+'
84     YDS_5_9m = 12, '5.9-'
85     YDS_5_9 = 13, '5.9'
86     YDS_5_9p = 14, '5.9+'
87     YDS_5_10a = 15, '5.10a'
88     YDS_5_10b = 16, '5.10b'
89     YDS_5_10c = 17, '5.10c'
90     YDS_5_10d = 18, '5.10d'
91     YDS_5_11a = 19, '5.11a'
92     YDS_5_11b = 20, '5.11b'
93     YDS_5_11c = 21, '5.11c'
94     YDS_5_11d = 22, '5.11d'
95     YDS_5_12a = 23, '5.12a'
96     YDS_5_12b = 24, '5.12b'
97     YDS_5_12c = 25, '5.12c'
98     YDS_5_12d = 26, '5.12d'
99     YDS_5_13a = 27, '5.13a'
100     YDS_5_13b = 28, '5.13b'
101     YDS_5_13c = 29, '5.13c'
102     YDS_5_13d = 30, '5.13d'
103     YDS_5_14a = 31, '5.14a'
104     YDS_5_14b = 32, '5.14b'
105     YDS_5_14c = 33, '5.14c'
106     YDS_5_14d = 34, '5.14d'
107     YDS_5_15a = 35, '5.15a'
108     YDS_5_15b = 36, '5.15b'
109     YDS_5_15c = 37, '5.15c'
110     YDS_5_15d = 38, '5.15d'
111
112 class Safety(models.IntegerChoices):
113     G = 0, 'G'
114     PG = 1, 'PG'
115     PG13 = 2, 'PG13'
116     R = 3, 'R'
117     X = 4, 'X'
118
119 class Pitch(models.Model):
120     route = models.ForeignKey(
121         Route,
122         on_delete=models.CASCADE,
123         related_name='pitches',
124     )
125     name = models.CharField(max_length=64, blank=True, null=True)
126     difficulty = models.PositiveIntegerField(choices=RouteDifficulty.choices)
127     safety = models.IntegerField(choices=Safety.choices)
128     notes = models.TextField(blank=True, null=True)
129
130     class Meta:
131         verbose_name_plural = 'pitches'
132
133     def __str__(self):
134         if self.name:
135             return '{} ({})'.format(self.name, self.difficulty)
136         return 'Pitch ({})'.format(self.difficulty)
137
138 class Cluster(models.Model):
139     area = models.ForeignKey(
140         Area,
141         on_delete=models.CASCADE,
142         related_name='clusters',
143     )
144     name = models.CharField(max_length=64)
145     notes = models.TextField(blank=True, null=True)
146
147     def __str__(self):
148         return self.name
149
150 class Boulder(models.Model):
151     cluster = models.ForeignKey(
152         Cluster,
153         on_delete=models.CASCADE,
154         related_name='boulders',
155     )
156     name = models.CharField(max_length=64)
157     notes = models.TextField(blank=True, null=True)
158
159     def __str__(self):
160         return self.name
161
162 class BoulderDifficylty(models.IntegerChoices):
163     V0 = 0, 'V0'
164     V1 = 1, 'V1'
165     V2 = 2, 'V2'
166     V3 = 3, 'V3'
167     V4 = 4, 'V4'
168     V5 = 5, 'V5'
169     V6 = 6, 'V6'
170     V7 = 7, 'V7'
171     V8 = 8, 'V8'
172     V9 = 9, 'V9'
173     V10 = 10, 'V10'
174     V11 = 11, 'V11'
175     V12 = 12, 'V12'
176     V13 = 13, 'V13'
177     V14 = 14, 'V14'
178     V15 = 15, 'V15'
179     V16 = 16, 'V16'
180     V17 = 17, 'V17'
181
182
183 class Problem(models.Model):
184     boulder = models.ForeignKey(
185         Boulder,
186         on_delete=models.CASCADE,
187         related_name='problems',
188     )
189     name = models.CharField(max_length=64)
190     difficulty = models.IntegerField(choices=BoulderDifficylty.choices)
191     safety = models.IntegerField(choices=Safety.choices)
192     mountain_project = models.URLField(blank=True, null=True)
193     notes = models.TextField(blank=True, null=True)
194
195     def __str__(self):
196         return '{} ({})'.format(self.name, self.difficulty)
197
198 class RouteTodo(models.Model):
199     user = models.ForeignKey(User, on_delete=models.CASCADE)
200     route = models.ForeignKey(Route, on_delete=models.CASCADE)
201
202 class ProblemTodo(models.Model):
203     user = models.ForeignKey(User, on_delete=models.CASCADE)
204     problem = models.ForeignKey(Problem, on_delete=models.CASCADE)
205
206 class RouteTick(models.Model):
207     user = models.ForeignKey(User, on_delete=models.CASCADE)
208     route = models.ForeignKey(Route, on_delete=models.CASCADE)
209     timestamp = models.DateTimeField()
210     notes = models.TextField(blank=True, null=True)
211
212 class ProblemTick(models.Model):
213     user = models.ForeignKey(User, on_delete=models.CASCADE)
214     problem = models.ForeignKey(Problem, on_delete=models.CASCADE)
215     timestamp = models.DateTimeField()
216     notes = models.TextField(blank=True, null=True)