From c12d70e0fc2e3552ade91ee120e0774c8af37e4e Mon Sep 17 00:00:00 2001
From: Noah Jonah Gente <fu2662cw@mi.fu-berlin.de>
Date: Tue, 8 Jun 2021 09:56:54 +0200
Subject: [PATCH] Create django admin command for seeding the database

---
 README.md                                     |   8 +-
 unisportomat/quiz/management/__init__.py      |   0
 .../quiz/management/commands/__init__.py      |   0
 .../quiz/management/commands/seed_db.py       | 118 ++++++++++++++++++
 unisportomat/quiz/tests.py                    |  29 ++++-
 5 files changed, 150 insertions(+), 5 deletions(-)
 create mode 100644 unisportomat/quiz/management/__init__.py
 create mode 100644 unisportomat/quiz/management/commands/__init__.py
 create mode 100644 unisportomat/quiz/management/commands/seed_db.py

diff --git a/README.md b/README.md
index ad37acf..b8554f8 100644
--- a/README.md
+++ b/README.md
@@ -72,14 +72,14 @@ python manage.py runserver
 If successful, you can now see the running server in your browser at `http://127.0.0.1:8000`.
 
 ## Populate the database with test data
-The json-Files in quiz/fixtures define some test data. To load the test data into your database run
+To populate the database with some test data run
 ```
-python manage.py loaddata quiz/fixtures/*.json
+python manage.py seed_db
 ```
-This will replace all your database content with the content defined in the fixtures. 
+All the existing data from your database will be lost!
 
 ## Use the django admin interface to view and edit data during development
 If you started the server as described above, you can access the django admin interface on
 [localhost:8000/admin](localhost:8000/admin).   
-If you loaded the data from the fixtures you can login with username: "admin" and password: "password"
+If you seeded the database you can login with username: "admin" and password: "password"
 
diff --git a/unisportomat/quiz/management/__init__.py b/unisportomat/quiz/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/unisportomat/quiz/management/commands/__init__.py b/unisportomat/quiz/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/unisportomat/quiz/management/commands/seed_db.py b/unisportomat/quiz/management/commands/seed_db.py
new file mode 100644
index 0000000..5ad94a2
--- /dev/null
+++ b/unisportomat/quiz/management/commands/seed_db.py
@@ -0,0 +1,118 @@
+"""
+Seeds the database with test data.
+You can call this by python manage.py seed_db
+"""
+
+import random
+
+from django.core.files.uploadedfile import SimpleUploadedFile
+from django.contrib.auth import get_user_model
+from django.core.management import call_command
+from django.core.management.base import BaseCommand
+from quiz.models import (
+    Sport,
+    Criterion,
+    Question,
+    CallToMove,
+    KnowledgeSnack,
+)
+
+
+class Command(BaseCommand):
+    """
+    Seeds the database with test data.
+    You can call this by python manage.py seed_db
+    """
+
+    help = "Seeds the database with test data"
+
+    def add_arguments(self, parser):
+        """
+        Add arguments to command that can be added to the command in command line
+        In this case there's only one arg that you can call by
+        python manage.py seed_db --yes
+        """
+        parser.add_argument(
+            "-y",
+            "--yes",
+            action="store_true",
+            help="Don't ask to confirm database flushing",
+        )
+
+    def handle(self, *args, **options):
+        """Create some objects for all models"""
+
+        # delete all present database entries (necessary because of unique constraints)
+        call_command("flush", "--no-input" if options["yes"] else [])
+
+        # Create admin user for using django admin interface during development
+        admin = get_user_model().objects.create_superuser("admin", password="password")
+        admin.save()
+
+        # Create sports
+        sports_names = [
+            "After Work Fitness",
+            "Ballett",
+            "Basketball",
+            "Beachvolleyball",
+            "Bouldern",
+        ]
+        for name in sports_names:
+            Sport(name=name).save()
+
+        # Create criteria
+        criteria_names = [
+            "Einzelsport",
+            "Mannschaftssport",
+            "Ausdauer",
+            "Kraft",
+            "Kampfsport",
+        ]
+        for name in criteria_names:
+            Criterion(name=name).save()
+
+        # Create ratings for all sports and criterions
+        for sport in Sport.objects.all():
+            for criterion in Criterion.objects.all():
+                sport.rate(criterion, random.randint(1, 10))
+
+        # Create questions
+        questions = [
+            "Ich würde am liebsten gemeinsam mit anderen trainieren.",
+            "Teamgeist und Wir-Gefühl sind für mich beim Sport eine große Motivation.",
+            "Ich betreibe lieber alleine Sport.",
+            "Ich bin bereit, mir ggf. Material für die Sportart zu kaufen.",
+            "Ich bevorzuge das Sportangebot draußen in der Natur vor dem Indoor-Angebot.",
+        ]
+
+        for number, criterion in enumerate(Criterion.objects.all()):
+            Question(text=questions[number], criterion=criterion).save()
+
+        # Create Calls to Move
+        calls_to_move = [
+            "Kreise deine Schultern vor der nächsten Frage 3x nach hinten",
+            "Stehe auf, beuge dich mit gestrecktem Rücken nach vorne und greife deinen Stuhl.",
+            "Mache vor der nächsten Frage 3 Jumping Jacks",
+        ]
+        image = SimpleUploadedFile(
+            name="test_image.png",
+            content=open("quiz/fixtures/images/test_image.png", "rb").read(),
+            content_type="image/png",
+        )
+
+        for text in calls_to_move:
+            CallToMove(text=text, image=image).save()
+
+        # Create Knowledge Snacks
+        knowledge_snacks = [
+            "Dass Treppensteigen fast 5x so viele Kalorien verbrennt, wie das Nutzen des Aufzuges?",
+            "Dass das Spielemobil zur Mittagszeit immer auf dem Campus unterwegs ist?",
+            "Dass regelmäßige Bewegung Herz-Kreislauf-Erkrankungen vorbeugt?",
+        ]
+        image = SimpleUploadedFile(
+            name="logo.png",
+            content=open("quiz/fixtures/images/logo.png", "rb").read(),
+            content_type="image/png",
+        )
+        for text in knowledge_snacks:
+            KnowledgeSnack(text=text, image=image).save()
diff --git a/unisportomat/quiz/tests.py b/unisportomat/quiz/tests.py
index 642c683..dda0956 100644
--- a/unisportomat/quiz/tests.py
+++ b/unisportomat/quiz/tests.py
@@ -5,9 +5,17 @@ import shutil
 import tempfile
 
 from django.core.files.uploadedfile import SimpleUploadedFile
+from django.core.management import call_command
 from django.test import TestCase, override_settings
 from django.conf import settings
-from .models import Sport, Criterion, CallToMove, KnowledgeSnack, Question
+from .models import (
+    Sport,
+    Criterion,
+    CriterionRating,
+    CallToMove,
+    KnowledgeSnack,
+    Question,
+)
 
 
 class SportModelTest(TestCase):
@@ -249,3 +257,22 @@ class FixturesTest(TestCase):
             "als die Nutzung des Aufzuges?",
         )
         self.assertEqual(knowledge_snack.image.name, "logo.png")
+
+
+class SeedingTest(TestCase):
+    """Tests the seed_db command in quiz/management/commands"""
+
+    def test_seed_with_complete_data(self):
+        """If seed_db is called then there exists a certain number of elements per model"""
+
+        # call the seed command without asking for confirmation
+        call_command("seed_db", ["--yes"])
+
+        n_sports = 5
+        n_criteria = 5
+        self.assertEqual(Sport.objects.count(), n_sports)
+        self.assertEqual(Criterion.objects.count(), n_criteria)
+        self.assertEqual(CriterionRating.objects.count(), n_sports * n_criteria)
+        self.assertEqual(Question.objects.count(), n_criteria)
+        self.assertEqual(CallToMove.objects.count(), 3)
+        self.assertEqual(KnowledgeSnack.objects.count(), 3)
-- 
GitLab