mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-07-18 15:20:19 +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.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@ -16,14 +16,17 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ChallengeCategory',
|
name='Challenge',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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={
|
options={
|
||||||
'verbose_name': 'challenge category',
|
'verbose_name': 'challenge',
|
||||||
'verbose_name_plural': 'challenge categories',
|
'verbose_name_plural': 'challenges',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -32,7 +35,7 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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, unique=True, verbose_name='name')),
|
||||||
('description', models.CharField(max_length=255, verbose_name='description')),
|
('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')),
|
('rank', models.PositiveIntegerField(verbose_name='rank')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@ -40,21 +43,6 @@ class Migration(migrations.Migration):
|
|||||||
'verbose_name_plural': 'Families',
|
'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(
|
migrations.CreateModel(
|
||||||
name='Achievement',
|
name='Achievement',
|
||||||
fields=[
|
fields=[
|
||||||
|
@ -11,16 +11,17 @@ class Family(models.Model):
|
|||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
verbose_name=_('name'),
|
verbose_name=_('name'),
|
||||||
unique=True
|
unique=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
description = models.CharField(
|
description = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
verbose_name=_('description')
|
verbose_name=_('description'),
|
||||||
)
|
)
|
||||||
|
|
||||||
score = models.PositiveIntegerField(
|
score = models.PositiveIntegerField(
|
||||||
verbose_name=_('score')
|
verbose_name=_('score'),
|
||||||
|
default=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
rank = models.PositiveIntegerField(
|
rank = models.PositiveIntegerField(
|
||||||
@ -34,6 +35,36 @@ class Family(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
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):
|
class FamilyMembership(models.Model):
|
||||||
user = models.OneToOneField(
|
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, )
|
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):
|
class Challenge(models.Model):
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
@ -94,15 +110,18 @@ class Challenge(models.Model):
|
|||||||
verbose_name=_('points'),
|
verbose_name=_('points'),
|
||||||
)
|
)
|
||||||
|
|
||||||
category = models.ForeignKey(
|
obtained = models.PositiveIntegerField(
|
||||||
ChallengeCategory,
|
verbose_name=_('obtained'),
|
||||||
verbose_name=_('category'),
|
default=0,
|
||||||
on_delete=models.PROTECT
|
|
||||||
)
|
)
|
||||||
|
|
||||||
obtained = models.PositiveIntegerField(
|
@transaction.atomic
|
||||||
verbose_name=_('obtained')
|
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:
|
class Meta:
|
||||||
verbose_name = _('challenge')
|
verbose_name = _('challenge')
|
||||||
@ -136,20 +155,6 @@ class Achievement(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return _('Challenge {challenge} carried out by Family {family}').format(challenge=self.challenge.name, family=self.family.name, )
|
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
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
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.family = Family.objects.select_for_update().get(pk=self.family_id)
|
||||||
self.challenge = Challenge.objects.select_for_update().get(pk=self.challenge_id)
|
self.challenge = Challenge.objects.select_for_update().get(pk=self.challenge_id)
|
||||||
challenge_points = self.challenge.points
|
|
||||||
is_new = self.pk is None
|
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:
|
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.refresh_from_db()
|
||||||
self.challenge.obtained += 1
|
self.challenge.obtained += 1
|
||||||
self.challenge._force_save = True
|
self.challenge._force_save = True
|
||||||
self.challenge.save()
|
self.challenge.save()
|
||||||
|
|
||||||
self.__class__.update_ranking()
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def delete(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -183,20 +183,15 @@ class Achievement(models.Model):
|
|||||||
"""
|
"""
|
||||||
# Get the family and challenge before deletion
|
# Get the family and challenge before deletion
|
||||||
self.family = Family.objects.select_for_update().get(pk=self.family_id)
|
self.family = Family.objects.select_for_update().get(pk=self.family_id)
|
||||||
challenge_points = self.challenge.points
|
|
||||||
|
|
||||||
# Delete the achievement
|
# Delete the achievement
|
||||||
super().delete(*args, **kwargs)
|
super().delete(*args, **kwargs)
|
||||||
|
|
||||||
# Remove points from the family
|
# Remove points from the family
|
||||||
self.family.refresh_from_db()
|
self.family.refresh_from_db()
|
||||||
self.family.score -= challenge_points
|
self.family.update_score()
|
||||||
self.family._force_save = True
|
|
||||||
self.family.save()
|
|
||||||
|
|
||||||
self.challenge.refresh_from_db()
|
self.challenge.refresh_from_db()
|
||||||
self.challenge.obtained -= 1
|
self.challenge.obtained -= 1
|
||||||
self.challenge._force_save = True
|
self.challenge._force_save = True
|
||||||
self.challenge.save()
|
self.challenge.save()
|
||||||
|
|
||||||
self.__class__.update_ranking()
|
|
||||||
|
Reference in New Issue
Block a user