From e34ad583c74608c09b83459225d779b8b5a7fc7f Mon Sep 17 00:00:00 2001
From: Noah Jonah Gente <fu2662cw@mi.fu-berlin.de>
Date: Mon, 24 May 2021 20:43:40 +0200
Subject: [PATCH] Prevent Criterion-Rating to be recreated on change

---
 unisportomat/quiz/models.py | 10 +++++++---
 unisportomat/quiz/tests.py  | 30 +++++++++++++++++++++++-------
 2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/unisportomat/quiz/models.py b/unisportomat/quiz/models.py
index 84b3574..a3b25fd 100644
--- a/unisportomat/quiz/models.py
+++ b/unisportomat/quiz/models.py
@@ -12,7 +12,7 @@ class CriterionRating(models.Model):
     """
 
     rating = models.IntegerField(
-        validators=[MaxValueValidator(10), MinValueValidator(0)]
+        validators=[MaxValueValidator(10), MinValueValidator(1)]
     )
     criterion = models.ForeignKey("Criterion", on_delete=models.CASCADE)
     sport = models.ForeignKey("Sport", on_delete=models.CASCADE)
@@ -34,8 +34,12 @@ class Sport(models.Model):
 
     def rate(self, criterion, rating):
         """Defines how much (rating) the sport meets the given criterion"""
-        rating = CriterionRating(sport=self, criterion=criterion, rating=rating)
-        rating.save()
+        rating_obj, _ = CriterionRating.objects.get_or_create(
+            sport=self, criterion=criterion, defaults={"rating": rating}
+        )
+        rating_obj.rating = rating
+        rating_obj.save()
+        return rating_obj
 
     def get_rating(self, criterion):
         """Returns how much the sport meets the given criterion"""
diff --git a/unisportomat/quiz/tests.py b/unisportomat/quiz/tests.py
index 05790a7..3c8a3f0 100644
--- a/unisportomat/quiz/tests.py
+++ b/unisportomat/quiz/tests.py
@@ -9,8 +9,10 @@ class SportModelTest(TestCase):
 
     def setUp(self):
         self.name = "HIIT"
-        self.url = "https://www.buchsys.de/fu-berlin/angebote/aktueller_zeitraum/_HIIT_" \
-                   "-_High_Intensity_Interval_Training___HOME.html "
+        self.url = (
+            "https://www.buchsys.de/fu-berlin/angebote/aktueller_zeitraum/_HIIT_"
+            "-_High_Intensity_Interval_Training___HOME.html "
+        )
 
         self.test_sport = Sport(
             name=self.name,
@@ -20,7 +22,7 @@ class SportModelTest(TestCase):
         self.test_sport.save()
 
     def test_sport_can_be_created(self):
-        """ New sport is written to the database """
+        """New sport is written to the database"""
         test_sport = Sport.objects.first()
         self.assertEqual(test_sport.name, self.name)
         self.assertEqual(test_sport.url, self.url)
@@ -28,10 +30,13 @@ class SportModelTest(TestCase):
 
 class CriterionRatingTest(TestCase):
     """Tests the Relation between Sport and Criterion"""
+
     def setUp(self):
         self.name = "HIIT"
-        self.url = "https://www.buchsys.de/fu-berlin/angebote/aktueller_zeitraum/_HIIT_" \
-                   "-_High_Intensity_Interval_Training___HOME.html "
+        self.url = (
+            "https://www.buchsys.de/fu-berlin/angebote/aktueller_zeitraum/_HIIT_"
+            "-_High_Intensity_Interval_Training___HOME.html "
+        )
 
         self.test_sport = Sport(
             name=self.name,
@@ -44,17 +49,28 @@ class CriterionRatingTest(TestCase):
         self.criterion.save()
 
     def test_can_rate_criterion_for_sport(self):
-        """ A rating for a specific criterion can be added to a sport """
+        """A rating for a specific criterion can be added to a sport"""
         self.test_sport.rate(self.criterion, 10)
         self.assertEqual(self.test_sport.criteria_ratings.first(), self.criterion)
         self.assertEqual(self.test_sport.get_rating(self.criterion), 10)
 
+    def test_rating_can_be_changed(self):
+        """
+        If a sport is rated again then the corresponding relation is changed,
+        instead of recreated
+        """
+        first_rating_object = self.test_sport.rate(self.criterion, 10)
+        second_rating_object = self.test_sport.rate(self.criterion, 8)
+        self.assertEqual(first_rating_object, second_rating_object)
+        self.assertEqual(self.test_sport.get_rating(criterion=self.criterion), 8)
+
 
 class CriterionModelTest(TestCase):
     """Tests the Criterion model"""
+
     def test_criterion_can_be_created(self):
         """New criterion is saved to the db"""
         name = "Einzelsport"
         Criterion(name=name).save()
-        test_criterion=Criterion.objects.first()
+        test_criterion = Criterion.objects.first()
         self.assertEqual(test_criterion.name, name)
-- 
GitLab