1 from django.contrib.auth.models import User
2 from django.core.exceptions import ValidationError
3 from django.db import models
4 from django.db.models import Q
7 def __xor__(self, other):
8 return (self & (~other)) | ((~self) & other)
12 BOULDER_DIFFICULTY_CHOICES = (
32 class Boulder(models.Model):
33 name = models.CharField(max_length=64)
34 difficulty = models.CharField(
35 choices=BOULDER_DIFFICULTY_CHOICES,
38 mountainproject = models.URLField(blank=True)
41 return '{} ({})'.format(self.name, self.difficulty)
43 PITCH_DIFFICULTY_CHOICES = (
85 class Pitch(models.Model):
86 order = models.PositiveSmallIntegerField()
87 route = models.ForeignKey(
89 on_delete=models.CASCADE,
90 related_name='pitches',
92 difficulty = models.CharField(
93 choices=PITCH_DIFFICULTY_CHOICES,
96 name = models.CharField(blank=True, max_length=32)
102 return 'P{} ({})'.format(self.order, self.difficulty)
104 PROTECTION_STYLE_CHOICES = (
106 ('toprope', 'Top Rope'),
110 class Route(models.Model):
111 name = models.CharField(max_length=64)
112 protection_style = models.CharField(max_length=8, choices=PROTECTION_STYLE_CHOICES)
113 mountainproject = models.URLField(blank=True)
115 # TODO Write test for this
117 def difficulty(self):
118 return self.pitches.order_by('-difficulty').first().difficulty
121 return '{} ({})'.format(self.name, self.difficulty)
123 ATTEMPT_RESULT_CHOICES = (
128 PROTECTION_CHOICES = (
136 class Attempt(models.Model):
137 user = models.ForeignKey(User, on_delete=models.CASCADE)
138 date = models.DateField()
139 notes = models.TextField()
140 boulder = models.ForeignKey('Boulder', null=True, on_delete=models.PROTECT, related_name='attempts')
141 route = models.ForeignKey('Route', null=True, on_delete=models.PROTECT, related_name='attempts')
142 result = models.CharField(max_length=8, choices=ATTEMPT_RESULT_CHOICES)
143 prior_knowledge = models.BooleanField(default=True)
144 protection_used = models.CharField(max_length=8, choices=PROTECTION_CHOICES)
148 models.CheckConstraint(
149 check=(Q(boulder__isnull=True) ^ Q(route__isnull=True)),
150 name='attempt_boulder_xor_route',
157 ('onsight', 'On Sight'),
159 ('project', 'Project'),
163 class Todo(models.Model):
164 user = models.ForeignKey(User, on_delete=models.CASCADE)
165 notes = models.TextField()
166 protection = models.CharField(max_length=8, choices=PROTECTION_CHOICES)
167 boulder = models.ForeignKey('Boulder', null=True, on_delete=models.PROTECT, related_name='todos')
168 route = models.ForeignKey('Route', null=True, on_delete=models.PROTECT, related_name='todos')
169 style = models.CharField(max_length=8, choices=STYLE_CHOICES)
173 models.CheckConstraint(
174 check=(Q(boulder__isnull=True) ^ Q(route__isnull=True)),
175 name='todo_boulder_xor_route',
179 ordering = ('route__name',)
189 return '{} {}'.format(self.style, climb)