Add some models
authorDavid Kerkeslager <kerkeslager@gmail.com>
Thu, 25 Feb 2021 19:27:53 +0000 (14:27 -0500)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Thu, 25 Feb 2021 19:27:53 +0000 (14:27 -0500)
core/settings.py
tickle/migrations/0001_initial.py [new file with mode: 0644]
tickle/models.py

index 3caa931..296d506 100644 (file)
@@ -37,6 +37,8 @@ INSTALLED_APPS = [
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
+
+    'tickle',
 ]
 
 MIDDLEWARE = [
diff --git a/tickle/migrations/0001_initial.py b/tickle/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..7955d21
--- /dev/null
@@ -0,0 +1,95 @@
+# Generated by Django 3.1.7 on 2021-02-25 19:26
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Boulder',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=64)),
+                ('mountainproject', models.URLField(null=True)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='BoulderDifficulty',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('order', models.PositiveSmallIntegerField()),
+                ('name', models.CharField(max_length=8)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Route',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=64)),
+                ('protection_style', models.CharField(choices=[('sport', 'Sport'), ('toprope', 'Top Rope'), ('trad', 'Trad')], max_length=8)),
+                ('mountainproject', models.URLField(null=True)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='RouteDifficulty',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('order', models.PositiveSmallIntegerField()),
+                ('name', models.CharField(max_length=8)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Todo',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('notes', models.TextField()),
+                ('protection', models.CharField(choices=[('none', 'None'), ('bolts', 'Bolts'), ('gear', 'Gear'), ('pad', 'Pad'), ('tr', 'Top Rope')], max_length=8)),
+                ('boulder', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='todos', to='tickle.boulder')),
+                ('route', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='todos', to='tickle.route')),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Pitch',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('difficulty', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='pitches', to='tickle.routedifficulty')),
+                ('route', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pitches', to='tickle.route')),
+            ],
+        ),
+        migrations.AddField(
+            model_name='boulder',
+            name='difficulty',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='boulders', to='tickle.boulderdifficulty'),
+        ),
+        migrations.CreateModel(
+            name='Attempt',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('notes', models.TextField()),
+                ('result', models.CharField(choices=[('send', 'Sent'), ('fall', 'Fall')], max_length=8)),
+                ('prior_knowledge', models.BooleanField(default=True)),
+                ('protection_used', models.CharField(choices=[('none', 'None'), ('bolts', 'Bolts'), ('gear', 'Gear'), ('pad', 'Pad'), ('tr', 'Top Rope')], max_length=8)),
+                ('boulder', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='attempts', to='tickle.boulder')),
+                ('route', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='attempts', to='tickle.route')),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+        migrations.AddConstraint(
+            model_name='todo',
+            constraint=models.CheckConstraint(check=models.Q(models.Q(('boulder__isnull', True), models.Q(_negated=True, route__isnull=True)), models.Q(models.Q(_negated=True, boulder__isnull=True), ('route__isnull', True)), _connector='OR'), name='todo_boulder_xor_route'),
+        ),
+        migrations.AddConstraint(
+            model_name='attempt',
+            constraint=models.CheckConstraint(check=models.Q(models.Q(('boulder__isnull', True), models.Q(_negated=True, route__isnull=True)), models.Q(models.Q(_negated=True, boulder__isnull=True), ('route__isnull', True)), _connector='OR'), name='attempt_boulder_xor_route'),
+        ),
+    ]
index 71a8362..268d7b0 100644 (file)
@@ -1,3 +1,108 @@
+from django.contrib.auth.models import User
+from django.core.exceptions import ValidationError
 from django.db import models
+from django.db.models import Q
 
-# Create your models here.
+class QQ:
+    def __xor__(self, other):
+        return (self & (~other)) | ((~self) & other)
+
+Q.__bases__ += (QQ, )
+
+class Boulder(models.Model):
+    name = models.CharField(max_length=64)
+    difficulty = models.ForeignKey(
+        'BoulderDifficulty',
+        null=True,
+        on_delete=models.PROTECT,
+        related_name='boulders',
+    )
+    mountainproject = models.URLField(null=True)
+
+class BoulderDifficulty(models.Model):
+    order = models.PositiveSmallIntegerField()
+    name = models.CharField(max_length=8)
+
+class Pitch(models.Model):
+    route = models.ForeignKey(
+        'Route',
+        on_delete=models.CASCADE,
+        related_name='pitches',
+    )
+    difficulty = models.ForeignKey(
+        'RouteDifficulty',
+        on_delete=models.PROTECT,
+        related_name='pitches',
+    )
+
+PROTECTION_STYLE_CHOICES = (
+    ('sport', 'Sport'),
+    ('toprope', 'Top Rope'),
+    ('trad', 'Trad'),
+)
+
+class Route(models.Model):
+    name = models.CharField(max_length=64)
+    protection_style = models.CharField(max_length=8, choices=PROTECTION_STYLE_CHOICES)
+    mountainproject = models.URLField(null=True)
+
+    # TODO Write test for this
+    @property
+    def difficulty(self):
+        return self.pitches.order_by('-difficulty__order').first().difficulty
+
+class RouteDifficulty(models.Model):
+    order = models.PositiveSmallIntegerField()
+    name = models.CharField(max_length=8)
+
+ATTEMPT_RESULT_CHOICES = (
+    ('send', 'Sent'),
+    ('fall', 'Fall'),
+)
+
+PROTECTION_CHOICES = (
+    ('none', 'None'),
+    ('bolts', 'Bolts'),
+    ('gear', 'Gear'),
+    ('pad', 'Pad'),
+    ('tr', 'Top Rope'),
+)
+
+class Attempt(models.Model):
+    user = models.ForeignKey(User, on_delete=models.CASCADE)
+    notes = models.TextField()
+    boulder = models.ForeignKey('Boulder', null=True, on_delete=models.PROTECT, related_name='attempts')
+    route = models.ForeignKey('Route', null=True, on_delete=models.PROTECT, related_name='attempts')
+    result = models.CharField(max_length=8, choices=ATTEMPT_RESULT_CHOICES)
+    prior_knowledge = models.BooleanField(default=True)
+    protection_used = models.CharField(max_length=8, choices=PROTECTION_CHOICES)
+
+    class Meta:
+        constraints = (
+            models.CheckConstraint(
+                check=(Q(boulder__isnull=True) ^ Q(route__isnull=True)),
+                name='attempt_boulder_xor_route',
+            ),
+        )
+
+STYLE_CHOICES = (
+    ('onsight', 'On Sight'),
+    ('flash', 'Flash'),
+    ('complete', 'Complete'),
+    ('project', 'project'),
+)
+
+class Todo(models.Model):
+    user = models.ForeignKey(User, on_delete=models.CASCADE)
+    notes = models.TextField()
+    protection = models.CharField(max_length=8, choices=PROTECTION_CHOICES)
+    boulder = models.ForeignKey('Boulder', null=True, on_delete=models.PROTECT, related_name='todos')
+    route = models.ForeignKey('Route', null=True, on_delete=models.PROTECT, related_name='todos')
+
+    class Meta:
+        constraints = (
+            models.CheckConstraint(
+                check=(Q(boulder__isnull=True) ^ Q(route__isnull=True)),
+                name='todo_boulder_xor_route',
+            ),
+        )