diff --git a/vrobbler/apps/people/apps.py b/vrobbler/apps/people/apps.py new file mode 100644 index 0000000..74ec7a3 --- /dev/null +++ b/vrobbler/apps/people/apps.py @@ -0,0 +1,9 @@ +from django.apps import AppConfig + + +class PeopleConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "people" + + def ready(self): + import people.signals # noqa diff --git a/vrobbler/apps/people/management/__init__.py b/vrobbler/apps/people/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vrobbler/apps/people/management/commands/__init__.py b/vrobbler/apps/people/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vrobbler/apps/people/management/commands/backfill_scrobble_counts.py b/vrobbler/apps/people/management/commands/backfill_scrobble_counts.py new file mode 100644 index 0000000..a89805f --- /dev/null +++ b/vrobbler/apps/people/management/commands/backfill_scrobble_counts.py @@ -0,0 +1,15 @@ +from django.core.management.base import BaseCommand + +from people.models import Person + + +class Command(BaseCommand): + help = "Backfill scrobble counts for all people" + + def handle(self, *args, **options): + for person in Person.objects.all(): + person.update_scrobble_count() + self.stdout.write( + f"{person.name}: {person.scrobble_count} scrobbles" + ) + self.stdout.write(self.style.SUCCESS("Done!")) diff --git a/vrobbler/apps/people/migrations/0004_add_scrobble_count.py b/vrobbler/apps/people/migrations/0004_add_scrobble_count.py new file mode 100644 index 0000000..c2675c6 --- /dev/null +++ b/vrobbler/apps/people/migrations/0004_add_scrobble_count.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.29 on 2026-03-21 15:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("people", "0003_person_created_by"), + ] + + operations = [ + migrations.AddField( + model_name="person", + name="scrobble_count", + field=models.IntegerField(default=0), + ), + ] diff --git a/vrobbler/apps/people/models.py b/vrobbler/apps/people/models.py index 2109ff7..2e528ec 100644 --- a/vrobbler/apps/people/models.py +++ b/vrobbler/apps/people/models.py @@ -11,13 +11,27 @@ class Person(TimeStampedModel): user = models.ForeignKey(User, on_delete=models.DO_NOTHING, **BNULL) created_by = models.ForeignKey( - User, on_delete=models.DO_NOTHING, **BNULL, related_name="created_people" + User, + on_delete=models.DO_NOTHING, + **BNULL, + related_name="created_people", ) name = models.CharField(max_length=100, **BNULL) bgstats_id = models.UUIDField(**BNULL) bgg_username = models.CharField(max_length=100, **BNULL) lichess_username = models.CharField(max_length=100, **BNULL) bio = models.TextField(**BNULL) + scrobble_count = models.IntegerField(default=0) def __str__(self): return self.name + + def update_scrobble_count(self): + from scrobbles.models import Scrobble + + count = Scrobble.objects.filter( + user=self.created_by, + log__with_people_ids__contains=self.id, + ).count() + self.scrobble_count = count + self.save(update_fields=["scrobble_count"]) diff --git a/vrobbler/apps/people/signals.py b/vrobbler/apps/people/signals.py new file mode 100644 index 0000000..86b3f24 --- /dev/null +++ b/vrobbler/apps/people/signals.py @@ -0,0 +1,28 @@ +from django.db.models.signals import post_save, post_delete +from django.dispatch import receiver + +from scrobbles.models import Scrobble + + +@receiver(post_save, sender=Scrobble) +def update_person_scrobble_count_on_save(sender, instance, **kwargs): + if instance.log and isinstance(instance.log, dict): + person_ids = instance.log.get("with_people_ids", []) + for person_id in person_ids: + from people.models import Person + + person = Person.objects.filter(id=person_id).first() + if person: + person.update_scrobble_count() + + +@receiver(post_delete, sender=Scrobble) +def update_person_scrobble_count_on_delete(sender, instance, **kwargs): + if instance.log and isinstance(instance.log, dict): + person_ids = instance.log.get("with_people_ids", []) + for person_id in person_ids: + from people.models import Person + + person = Person.objects.filter(id=person_id).first() + if person: + person.update_scrobble_count() diff --git a/vrobbler/apps/people/urls.py b/vrobbler/apps/people/urls.py index 88be3d2..76e4612 100644 --- a/vrobbler/apps/people/urls.py +++ b/vrobbler/apps/people/urls.py @@ -5,7 +5,9 @@ app_name = "people" urlpatterns = [ - path("people/", views.PersonCreateUpdateView.as_view(), name="person_form"), + path( + "people/", views.PersonCreateUpdateView.as_view(), name="person_form" + ), path( "people//edit/", views.PersonUpdateView.as_view(), diff --git a/vrobbler/apps/people/views.py b/vrobbler/apps/people/views.py index 77527de..4d56d2d 100644 --- a/vrobbler/apps/people/views.py +++ b/vrobbler/apps/people/views.py @@ -17,7 +17,9 @@ class PersonCreateUpdateView(generic.CreateView): def get_context_data(self, **kwargs): context_data = super().get_context_data(**kwargs) - context_data["people"] = Person.objects.filter(created_by=self.request.user) + context_data["people"] = Person.objects.filter( + created_by=self.request.user + ).order_by("-scrobble_count", "name") return context_data def form_valid(self, form): @@ -33,5 +35,7 @@ class PersonUpdateView(generic.UpdateView): def get_context_data(self, **kwargs): context_data = super().get_context_data(**kwargs) - context_data["people"] = Person.objects.filter(created_by=self.request.user) + context_data["people"] = Person.objects.filter( + created_by=self.request.user + ).order_by("-scrobble_count", "name") return context_data diff --git a/vrobbler/templates/people/person_form.html b/vrobbler/templates/people/person_form.html index 3cadd40..4e25d88 100644 --- a/vrobbler/templates/people/person_form.html +++ b/vrobbler/templates/people/person_form.html @@ -110,6 +110,9 @@ {% for person in people %}
  • {{ person.name }} + {% if person.scrobble_count > 0 %} + ({{ person.scrobble_count }} scrobbles) + {% endif %} Edit