mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-31 07:49:57 +01:00 
			
		
		
		
	Models fixed
This commit is contained in:
		| @@ -11,16 +11,17 @@ class Family(models.Model): | ||||
|     name = models.CharField( | ||||
|         max_length=255, | ||||
|         verbose_name=_('name'), | ||||
|         unique=True | ||||
|         unique=True, | ||||
|     ) | ||||
|  | ||||
|     description = models.CharField( | ||||
|         max_length=255, | ||||
|         verbose_name=_('description') | ||||
|         verbose_name=_('description'), | ||||
|     ) | ||||
|  | ||||
|     score = models.PositiveIntegerField( | ||||
|         verbose_name=_('score') | ||||
|         verbose_name=_('score'), | ||||
|         default=0, | ||||
|     ) | ||||
|  | ||||
|     rank = models.PositiveIntegerField( | ||||
| @@ -34,6 +35,36 @@ class Family(models.Model): | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | ||||
|     def update_score(self, *args, **kwargs): | ||||
|         challenge_set = Challenge.objects.select_for_update().filter(achievement__family=self) | ||||
|         points_sum = challenge_set.aggregate(models.Sum("points")) | ||||
|         self.score = points_sum["points__sum"] | ||||
|         self.save() | ||||
|         self.update_ranking() | ||||
|  | ||||
|     @staticmethod | ||||
|     def update_ranking(*args, **kwargs): | ||||
|         """ | ||||
|         Update ranking when adding or removing points | ||||
|         """ | ||||
|         family_set = Family.objects.select_for_update().all().order_by("-score") | ||||
|         for i in range(family_set.count()): | ||||
|             if i == 0 or family_set[i].score != family_set[i - 1].score: | ||||
|                 new_rank = i + 1 | ||||
|             family = family_set[i] | ||||
|             family.rank = new_rank | ||||
|             family._force_save = True | ||||
|             family.save() | ||||
|  | ||||
|     def save(self, *args, **kwargs): | ||||
|         if self.rank is None: | ||||
|             last_family = Family.objects.order_by("rank").last() | ||||
|             if last_family is None or last_family.score > self.score: | ||||
|                 self.rank = Family.objects.count() + 1 | ||||
|             else: | ||||
|                 self.rank = last_family.rank | ||||
|         super().save(*args, **kwargs) | ||||
|  | ||||
|  | ||||
| class FamilyMembership(models.Model): | ||||
|     user = models.OneToOneField( | ||||
| @@ -64,21 +95,6 @@ class FamilyMembership(models.Model): | ||||
|         return _('Family membership of {user} to {family}').format(user=self.user.username, family=self.family.name, ) | ||||
|  | ||||
|  | ||||
| class ChallengeCategory(models.Model): | ||||
|     name = models.CharField( | ||||
|         max_length=255, | ||||
|         verbose_name=_('name'), | ||||
|         unique=True, | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         verbose_name = _('challenge category') | ||||
|         verbose_name_plural = _('challenge categories') | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | ||||
|  | ||||
| class Challenge(models.Model): | ||||
|     name = models.CharField( | ||||
|         max_length=255, | ||||
| @@ -94,15 +110,18 @@ class Challenge(models.Model): | ||||
|         verbose_name=_('points'), | ||||
|     ) | ||||
|  | ||||
|     category = models.ForeignKey( | ||||
|         ChallengeCategory, | ||||
|         verbose_name=_('category'), | ||||
|         on_delete=models.PROTECT | ||||
|     obtained = models.PositiveIntegerField( | ||||
|         verbose_name=_('obtained'), | ||||
|         default=0, | ||||
|     ) | ||||
|  | ||||
|     obtained = models.PositiveIntegerField( | ||||
|         verbose_name=_('obtained') | ||||
|     ) | ||||
|     @transaction.atomic | ||||
|     def save(self, *args, **kwargs): | ||||
|         super().save(*args, **kwargs) | ||||
|         # Update families who already obtained this challenge | ||||
|         achievements = Achievement.objects.filter(challenge=self) | ||||
|         for achievement in achievements: | ||||
|             achievement.save() | ||||
|  | ||||
|     class Meta: | ||||
|         verbose_name = _('challenge') | ||||
| @@ -136,20 +155,6 @@ class Achievement(models.Model): | ||||
|     def __str__(self): | ||||
|         return _('Challenge {challenge} carried out by Family {family}').format(challenge=self.challenge.name, family=self.family.name, ) | ||||
|  | ||||
|     @classmethod | ||||
|     def update_ranking(cls, *args, **kwargs): | ||||
|         """ | ||||
|         Update ranking when adding or removing points | ||||
|         """ | ||||
|         family_set = cls.objects.select_for_update().all().order_by("-score") | ||||
|         for i in range(family_set.count()): | ||||
|             if i == 0 or family_set[i].score != family_set[i - 1].score: | ||||
|                 new_rank = i + 1 | ||||
|             family = family_set[i] | ||||
|             family.rank = new_rank | ||||
|             family._force_save = True | ||||
|             family.save() | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def save(self, *args, **kwargs): | ||||
|         """ | ||||
| @@ -157,25 +162,20 @@ class Achievement(models.Model): | ||||
|         """ | ||||
|         self.family = Family.objects.select_for_update().get(pk=self.family_id) | ||||
|         self.challenge = Challenge.objects.select_for_update().get(pk=self.challenge_id) | ||||
|         challenge_points = self.challenge.points | ||||
|         is_new = self.pk is None | ||||
|  | ||||
|         super.save(*args, **kwargs) | ||||
|         super().save(*args, **kwargs) | ||||
|  | ||||
|         # Only grant points when getting a new achievement | ||||
|         self.family.refresh_from_db() | ||||
|         self.family.update_score() | ||||
|  | ||||
|         # Count only when getting a new achievement | ||||
|         if is_new: | ||||
|             self.family.refresh_from_db() | ||||
|             self.family.score += challenge_points | ||||
|             self.family._force_save = True | ||||
|             self.family.save() | ||||
|  | ||||
|             self.challenge.refresh_from_db() | ||||
|             self.challenge.obtained += 1 | ||||
|             self.challenge._force_save = True | ||||
|             self.challenge.save() | ||||
|  | ||||
|             self.__class__.update_ranking() | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def delete(self, *args, **kwargs): | ||||
|         """ | ||||
| @@ -183,20 +183,15 @@ class Achievement(models.Model): | ||||
|         """ | ||||
|         # Get the family and challenge before deletion | ||||
|         self.family = Family.objects.select_for_update().get(pk=self.family_id) | ||||
|         challenge_points = self.challenge.points | ||||
|  | ||||
|         # Delete the achievement | ||||
|         super().delete(*args, **kwargs) | ||||
|  | ||||
|         # Remove points from the family | ||||
|         self.family.refresh_from_db() | ||||
|         self.family.score -= challenge_points | ||||
|         self.family._force_save = True | ||||
|         self.family.save() | ||||
|         self.family.update_score() | ||||
|  | ||||
|         self.challenge.refresh_from_db() | ||||
|         self.challenge.obtained -= 1 | ||||
|         self.challenge._force_save = True | ||||
|         self.challenge.save() | ||||
|  | ||||
|         self.__class__.update_ranking() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user