mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-07-18 07:10:18 +02:00
Models fixed
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
# Generated by Django 4.2.21 on 2025-07-04 19:05
|
||||
# Generated by Django 4.2.21 on 2025-07-06 16:07
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
@ -16,14 +16,17 @@ class Migration(migrations.Migration):
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ChallengeCategory',
|
||||
name='Challenge',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True, verbose_name='name')),
|
||||
('name', models.CharField(max_length=255, verbose_name='name')),
|
||||
('description', models.CharField(max_length=255, verbose_name='description')),
|
||||
('points', models.PositiveIntegerField(verbose_name='points')),
|
||||
('obtained', models.PositiveIntegerField(default=0, verbose_name='obtained')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'challenge category',
|
||||
'verbose_name_plural': 'challenge categories',
|
||||
'verbose_name': 'challenge',
|
||||
'verbose_name_plural': 'challenges',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
@ -32,7 +35,7 @@ class Migration(migrations.Migration):
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True, verbose_name='name')),
|
||||
('description', models.CharField(max_length=255, verbose_name='description')),
|
||||
('score', models.PositiveIntegerField(verbose_name='score')),
|
||||
('score', models.PositiveIntegerField(default=0, verbose_name='score')),
|
||||
('rank', models.PositiveIntegerField(verbose_name='rank')),
|
||||
],
|
||||
options={
|
||||
@ -40,21 +43,6 @@ class Migration(migrations.Migration):
|
||||
'verbose_name_plural': 'Families',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Challenge',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, verbose_name='name')),
|
||||
('description', models.CharField(max_length=255, verbose_name='description')),
|
||||
('points', models.PositiveIntegerField(verbose_name='points')),
|
||||
('obtained', models.PositiveIntegerField(verbose_name='obtained')),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='family.challengecategory', verbose_name='category')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'challenge',
|
||||
'verbose_name_plural': 'challenges',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Achievement',
|
||||
fields=[
|
||||
|
@ -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