Skip to content

Commit

Permalink
Réduit le nombre de requêtes SQL sur la page /mp/
Browse files Browse the repository at this point in the history
  • Loading branch information
philippemilink authored and Arnaud-D committed Aug 27, 2023
1 parent d535763 commit d17fe42
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 7 deletions.
3 changes: 2 additions & 1 deletion zds/mp/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ def get_private_topics_of_user(self, user_id):
super()
.get_queryset()
.filter(Q(participants__in=[user_id]) | Q(author=user_id))
.select_related("author")
.select_related("author__profile")
.prefetch_related("participants")
.distinct()
.order_by("-last_message__pubdate")
.all()
Expand Down
17 changes: 14 additions & 3 deletions zds/mp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ class Meta:
pubdate = models.DateTimeField("Date de création", auto_now_add=True, db_index=True)
objects = PrivateTopicManager()

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._cache_is_unread = dict()
self._cache_first_post = None

@staticmethod
def create(title, subtitle, author, recipients):
limit = PrivateTopic._meta.get_field("title").max_length
Expand Down Expand Up @@ -140,7 +145,10 @@ def first_post(self):
:return: PrivateTopic object first answer (PrivatePost)
:rtype: PrivatePost object or None
"""
return PrivatePost.objects.filter(privatetopic=self).order_by("position_in_topic").first()
if self._cache_first_post is None:
self._cache_first_post = PrivatePost.objects.filter(privatetopic=self).order_by("position_in_topic").first()

return self._cache_first_post

def last_read_post(self, user=None):
"""
Expand Down Expand Up @@ -212,7 +220,7 @@ def resolve_last_read_post_absolute_url(self, user=None):
return self.first_unread_post().get_absolute_url()

def resolve_last_post_pk_and_pos_read_by_user(self, user):
"""Determine the primary ey of position of the last post read by a user.
"""Determine the primary key of position of the last post read by a user.
:param user: the current (authenticated) user. Please do not try with unauthenticated user, il would lead to a \
useless request.
Expand Down Expand Up @@ -252,7 +260,10 @@ def is_unread(self, user=None):
if user is None:
user = get_current_user()

return is_privatetopic_unread(self, user)
if user not in self._cache_is_unread:
self._cache_is_unread[user] = is_privatetopic_unread(self, user)

return self._cache_is_unread[user]

def is_author(self, user):
"""
Expand Down
20 changes: 17 additions & 3 deletions zds/mp/tests/tests_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@

from zds.member.tests.factories import ProfileFactory
from zds.mp.tests.factories import PrivateTopicFactory, PrivatePostFactory
from zds.mp.models import mark_read, is_privatetopic_unread, is_reachable, NotParticipatingError, NotReachableError
from zds.mp.models import (
is_privatetopic_unread,
is_reachable,
mark_read,
NotParticipatingError,
NotReachableError,
PrivateTopic,
)

# by moment, i wrote the scenario to be simpler

Expand Down Expand Up @@ -105,14 +112,17 @@ def test_is_unread(self):
# post1 - user1 - read
# post2 - user2 - read
mark_read(self.topic1, self.user1)
self.assertTrue(self.topic1.is_unread(self.user1)) # cache is working
self.topic1 = PrivateTopic.objects.get(pk=self.topic1.pk) # get a new object to have an empty cache
self.assertFalse(self.topic1.is_unread(self.user1))

# scenario - topic1 :
# post1 - user1 - read
# post2 - user2 - read
# post3 - user2 - unread
PrivatePostFactory(privatetopic=self.topic1, author=self.user2, position_in_topic=3)

self.assertFalse(self.topic1.is_unread(self.user1)) # cache is working
self.topic1 = PrivateTopic.objects.get(pk=self.topic1.pk) # get a new object to have an empty cache
self.assertTrue(self.topic1.is_unread(self.user1))

def test_topic_never_read_get_last_read(self):
Expand Down Expand Up @@ -270,12 +280,16 @@ def test_mark_read(self, topic_read):
# post1 - user1 - read
# post2 - user2 - read
mark_read(self.topic1, self.profile1.user)
self.assertFalse(self.topic1.is_unread(self.profile1.user))
self.assertEqual(topic_read.send.call_count, 1)
self.assertTrue(self.topic1.is_unread(self.profile1.user)) # cache is working
self.topic1 = PrivateTopic.objects.get(pk=self.topic1.pk) # get a new object to have an empty cache
self.assertFalse(self.topic1.is_unread(self.profile1.user))

# scenario - topic1 :
# post1 - user1 - read
# post2 - user2 - read
# post3 - user2 - unread
PrivatePostFactory(privatetopic=self.topic1, author=self.profile2.user, position_in_topic=3)
self.assertFalse(self.topic1.is_unread(self.profile1.user)) # cache is working
self.topic1 = PrivateTopic.objects.get(pk=self.topic1.pk) # get a new object to have an empty cache
self.assertTrue(self.topic1.is_unread(self.profile1.user))

0 comments on commit d17fe42

Please sign in to comment.