Add caching for user basic info

This commit is contained in:
cuom1999 2023-10-10 19:37:36 -05:00
parent 7f854c40dd
commit ed287b6ff3
15 changed files with 110 additions and 33 deletions

View file

@ -126,7 +126,7 @@ class ProfileAdmin(VersionAdmin):
admin_user_admin.short_description = _("User")
def email(self, obj):
return obj.user.email
return obj.email
email.admin_order_field = "user__email"
email.short_description = _("Email")

View file

@ -40,9 +40,9 @@ def cache_wrapper(prefix, timeout=None):
if result == NONE_RESULT:
result = None
return result
result = func(*args, **kwargs)
if result is None:
result = NONE_RESULT
result = func(*args, **kwargs)
cache.set(cache_key, result, timeout)
return result

View file

@ -12,12 +12,12 @@ from . import registry
def gravatar(profile, size=80, default=None, profile_image=None, email=None):
if profile_image:
return profile_image
if profile and profile.profile_image:
return profile.profile_image.url
if profile and profile.cached_profile_image:
return profile.cached_profile_image.url
if profile:
email = email or profile.user.email
email = email or profile.email
if default is None:
default = profile.mute
default = profile.is_muted
gravatar_url = (
"//www.gravatar.com/avatar/"
+ hashlib.md5(utf8bytes(email.strip().lower())).hexdigest()

View file

@ -157,14 +157,14 @@ def item_title(item):
@registry.render_with("user/link.html")
def link_user(user):
if isinstance(user, Profile):
user, profile = user.user, user
profile = user
elif isinstance(user, AbstractUser):
profile = user.profile
elif type(user).__name__ == "ContestRankingProfile":
user, profile = user.user, user
profile = user
else:
raise ValueError("Expected profile or user, got %s" % (type(user),))
return {"user": user, "profile": profile}
return {"profile": profile}
@registry.function

View file

@ -0,0 +1,18 @@
# Generated by Django 3.2.18 on 2023-10-10 23:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("judge", "0171_update_notification"),
]
operations = [
migrations.AlterField(
model_name="profile",
name="rating",
field=models.IntegerField(db_index=True, default=None, null=True),
),
]

View file

@ -10,6 +10,9 @@ from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django.dispatch import receiver
from django.db.models.signals import post_save, pre_save
from fernet_fields import EncryptedCharField
from sortedm2m.fields import SortedManyToManyField
@ -202,7 +205,7 @@ class Profile(models.Model):
help_text=_("User will not be able to vote on problems' point values."),
default=False,
)
rating = models.IntegerField(null=True, default=None)
rating = models.IntegerField(null=True, default=None, db_index=True)
user_script = models.TextField(
verbose_name=_("user script"),
default="",
@ -256,6 +259,21 @@ class Profile(models.Model):
max_length=300,
)
@cache_wrapper(prefix="Pgbi")
def _get_basic_info(self):
return {
"first_name": self.user.first_name,
"last_name": self.user.last_name,
"email": self.user.email,
"username": self.user.username,
"mute": self.mute,
"profile_image": self.profile_image,
}
@cached_property
def _cached_info(self):
return self._get_basic_info()
@cached_property
def organization(self):
# We do this to take advantage of prefetch_related
@ -264,7 +282,27 @@ class Profile(models.Model):
@cached_property
def username(self):
return self.user.username
return self._cached_info["username"]
@cached_property
def first_name(self):
return self._cached_info["first_name"]
@cached_property
def last_name(self):
return self._cached_info["last_name"]
@cached_property
def email(self):
return self._cached_info["email"]
@cached_property
def is_muted(self):
return self._cached_info["mute"]
@cached_property
def cached_profile_image(self):
return self._cached_info["profile_image"]
@cached_property
def count_unseen_notifications(self):
@ -499,3 +537,18 @@ class OrganizationProfile(models.Model):
@classmethod
def get_most_recent_organizations(self, users):
return self.objects.filter(users=users).order_by("-last_visit")[:5]
@receiver([post_save], sender=User)
def on_user_save(sender, instance, **kwargs):
profile = instance.profile
profile._get_user.dirty(profile)
@receiver([pre_save], sender=Profile)
def on_profile_save(sender, instance, **kwargs):
if instance.id is None:
return
prev = sender.objects.get(id=instance.id)
if prev.mute != instance.mute or prev.profile_image != instance.profile_image:
instance._get_user.dirty(instance)

View file

@ -31,10 +31,9 @@ class Resolver(TemplateView):
for participation in self.contest.users.filter(virtual=0):
cnt_user += 1
users[str(cnt_user)] = {
"username": participation.user.user.username,
"name": participation.user.user.first_name
or participation.user.user.username,
"school": participation.user.user.last_name,
"username": participation.user.username,
"name": participation.user.first_name or participation.user.username,
"school": participation.user.last_name,
"last_submission": participation.cumtime_final,
"problems": {},
}