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