changeset 791:0ca691cccf8d

Utilize select_related() for user & user profiles. This commit also removes the caching of the avatar URL in the avatar template tag. This is because we are now using select_related, so we already have the profile & avatar when we get to the tag. Thus we don't need to waste time querying the cache. Removed an apparently unused member map template as well.
author Brian Neal <bgneal@gmail.com>
date Fri, 23 May 2014 21:52:41 -0500
parents 6a06080e7ca8
children 7429c98c8ece
files bio/templatetags/bio_tags.py comments/templatetags/comment_tags.py forums/views/main.py membermap/views.py sg101/templates/forums/display_post.html sg101/templates/membermap/markdown.html shoutbox/models.py shoutbox/views.py
diffstat 8 files changed, 49 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/bio/templatetags/bio_tags.py	Fri May 23 15:39:14 2014 -0500
+++ b/bio/templatetags/bio_tags.py	Fri May 23 21:52:41 2014 -0500
@@ -30,28 +30,15 @@
 @register.inclusion_tag('bio/avatar_tag.html')
 def avatar(user, profile_link=True, align='bottom'):
     """
-    Returns a dict of attributes for a user's avatar image.
+    Renders a user's avatar image.
 
-    If the user object has an attribute 'user_profile', this is assumed to be
-    the user's profile that has been pre-fetched. Otherwise, the cache is
-    consulted to retrieve the avatar info for the user. If there is a cache
-    miss, only then will we access the profile attribute to retrieve the profile
-    from the database.
+    For best results, ensure the user's profile has already been loaded (perhaps
+    via a select_related()). We no longer cache the avatar url because with
+    proper use of select_related we will have the user profile already so there
+    is no need to go spend time checking the cache.
 
     """
-    # img_info is a tuple that contains info about the avatar:
-    # (url, width, height)
-
-    if hasattr(user, 'user_profile'):
-        img_url = get_img_url(user.user_profile)
-    else:
-        # try the cache
-        cache_key = 'avatar_' + user.username
-        img_url = cache.get(cache_key)
-        if img_url is None:
-            profile = user.profile
-            img_url = get_img_url(profile)
-            cache.set(cache_key, img_url)
+    img_url = get_img_url(user.profile)
 
     title = user.username
     style = ''
--- a/comments/templatetags/comment_tags.py	Fri May 23 15:39:14 2014 -0500
+++ b/comments/templatetags/comment_tags.py	Fri May 23 21:52:41 2014 -0500
@@ -160,7 +160,7 @@
     Syntax:
         {% render_comment_list [object] %}
     """
-    qs = Comment.objects.for_object(object).select_related('user')
+    qs = Comment.objects.for_object(object).select_related('user', 'user__profile')
     return {
         'comments': qs,
         'STATIC_URL': settings.STATIC_URL,
--- a/forums/views/main.py	Fri May 23 15:39:14 2014 -0500
+++ b/forums/views/main.py	Fri May 23 21:52:41 2014 -0500
@@ -23,12 +23,12 @@
 
 import antispam
 import antispam.utils
-from bio.models import UserProfile, BadgeOwnership
+from bio.models import BadgeOwnership
 from core.paginator import DiggPaginator
 from core.functions import email_admins, quote_message
 
 from forums.models import (Forum, Topic, Post, FlaggedPost, TopicLastVisit,
-        ForumLastVisit, Attachment)
+        ForumLastVisit)
 from forums.forms import (NewTopicForm, NewPostForm, PostForm, MoveTopicForm,
         SplitTopicForm)
 from forums.unread import (get_forum_unread_status, get_topic_unread_status,
@@ -170,7 +170,9 @@
     topic.view_count = F('view_count') + 1
     topic.save(force_update=True)
 
-    posts = topic.posts.select_related('user')
+    posts = topic.posts.\
+                select_related('user', 'user__profile').\
+                prefetch_related('attachments')
 
     paginator = create_post_paginator(posts)
     page_num = get_page_num(request)
@@ -180,39 +182,23 @@
         raise Http404
     get_post_unread_status(topic, page.object_list, request.user)
 
-    # Attach user profiles to each post's user to avoid using
-    # get_user_profile() in the template.
-    users = set(post.user.id for post in page.object_list)
-
-    profiles = UserProfile.objects.filter(user__id__in=users).select_related()
-    profile_keys = [profile.id for profile in profiles]
-    user_profiles = dict((profile.user.id, profile) for profile in profiles)
+    # Get the BadgeOwnership & Badges for each user who has posted in the
+    # thread. This is done to save SQL queries in the template.
 
     last_post_on_page = None
+    profile_ids = []
     for post in page.object_list:
-        post.user.user_profile = user_profiles[post.user.id]
-        post.attach_list = []
         last_post_on_page = post
+        profile_ids.append(post.user.profile.pk)
 
-    # Attach badge ownership info to the user profiles to avoid lots
-    # of database hits in the template:
-    bos_qs = BadgeOwnership.objects.filter(
-            profile__id__in=profile_keys).select_related()
+    bo_qs = BadgeOwnership.objects.filter(profile__in=profile_ids).\
+                select_related()
     bos = collections.defaultdict(list)
-    for bo in bos_qs:
-        bos[bo.profile.id].append(bo)
+    for bo in bo_qs:
+        bos[bo.profile.pk].append(bo)
 
-    for user_id, profile in user_profiles.iteritems():
-        profile.badge_ownership = bos[profile.id]
-
-    # Attach any attachments
-    post_ids = [post.pk for post in page.object_list]
-    attachments = Attachment.objects.filter(post__in=post_ids).select_related(
-            'embed').order_by('order')
-
-    post_dict = dict((post.pk, post) for post in page.object_list)
-    for item in attachments:
-        post_dict[item.post.id].attach_list.append(item.embed)
+    for post in page.object_list:
+        post.user.profile.badge_ownership = bos[post.user.profile.pk]
 
     last_page = page_num == paginator.num_pages
 
@@ -468,8 +454,6 @@
     else:
         form = PostForm(instance=post, topic_name=topic_name)
 
-    post.user.user_profile = post.user.profile
-
     return render_to_response('forums/edit_post.html', {
         'forum': post.topic.forum,
         'topic': post.topic,
--- a/membermap/views.py	Fri May 23 15:39:14 2014 -0500
+++ b/membermap/views.py	Fri May 23 21:52:41 2014 -0500
@@ -57,9 +57,10 @@
         return HttpResponse(s, content_type='application/json')
 
     # Compute JSON for the map
-    entries = MapEntry.objects.all().select_related().order_by('user__username')
+    entries = MapEntry.objects.select_related('user', 'user__profile').\
+            order_by('user__username')
     users = []
-    user_ids = []
+    avatar_urls = []
     recent = []
     for entry in entries.iterator():
         users.append(dict(name=entry.user.username,
@@ -67,20 +68,17 @@
             lon=entry.lon,
             message=entry.html,
             ))
-        user_ids.append(entry.user.id)
+        avatar = entry.user.profile.avatar
+        if avatar and avatar.url:
+            avatar_urls.append(avatar.url)
+        else:
+            avatar_urls.append(None)
         recent.append((entry.date_updated, entry.user.username))
 
-    # Get avatars for all users
-    profiles = UserProfile.objects.filter(user__in=user_ids).select_related()
-    avatars = {}
-    for profile in profiles.iterator():
-        if profile.avatar and profile.avatar.url:
-            avatars[profile.user.username] = profile.avatar.url
-
     # Render the messages that go in the balloons
-    for user in users:
+    for user, avatar_url in zip(users, avatar_urls):
         user['message'] = render_to_string('membermap/balloon.html',
-                dict(user=user, avatar_url=avatars.get(user['name'])))
+                dict(user=user, avatar_url=avatar_url))
 
     # Produce the list of recent updates
     recent.sort(reverse=True)
--- a/sg101/templates/forums/display_post.html	Fri May 23 15:39:14 2014 -0500
+++ b/sg101/templates/forums/display_post.html	Fri May 23 21:52:41 2014 -0500
@@ -6,27 +6,27 @@
       <span class="post-author">{% profile_link post.user.username %}</span><br />
       {% avatar post.user %}<br />
       Joined: {{ post.user.date_joined|date:"M d, Y" }}<br />
-      Posts: {{ post.user.user_profile.forum_post_count }}<br />
-      {% if post.user.user_profile.location %}
-         {{ post.user.user_profile.location }}<br />
+      Posts: {{ post.user.profile.forum_post_count }}<br />
+      {% if post.user.profile.location %}
+         {{ post.user.profile.location }}<br />
       {% endif %}
-      {% if post.user.user_profile.country %}
-         {% flag_icon post.user.user_profile.country 'small' %}<br />
+      {% if post.user.profile.country %}
+         {% flag_icon post.user.profile.country 'small' %}<br />
       {% endif %}
-      {% for bo in post.user.user_profile.badge_ownership %}
+      {% for bo in post.user.profile.badge_ownership %}
          <img src="{{ bo.badge.image.url }}" alt="{{ bo.badge_count_str }}" title="{{ bo.badge_count_str }}" />
       {% endfor %}
       {% if user.is_authenticated %}
       <p>
       <a href="{% url 'messages-compose_to' post.user.username %}">
       <img src="{{ STATIC_URL }}icons/note.png" alt="PM" title="Send Private Message to {{ post.user.username }}" /></a>
-      {% if not post.user.user_profile.hide_email %}<a href="mailto:{{ post.user.email }}">
+      {% if not post.user.profile.hide_email %}<a href="mailto:{{ post.user.email }}">
          <img src="{{ STATIC_URL }}icons/email.png" alt="Email" title="Send Email to {{ post.user.username}}" /></a>{% endif %}
       </p>
       {% endif %}
    </td>
    <td class="forum-post-body">
-      <div class="forum-post-info quiet{% if post.user.user_profile.is_stranger %} stranger{% endif %}">
+      <div class="forum-post-info quiet{% if post.user.profile.is_stranger %} stranger{% endif %}">
       {% if post.unread %}<img src="{{ STATIC_URL }}icons/new.png" alt="New" title="New" />{% endif %}
       <a href="{{ post.get_absolute_url }}"><img src="{{ STATIC_URL }}icons/link.png" alt="Link" title="Link to this post" /></a>
          Posted on {% forum_date post.creation_date user %}
@@ -34,16 +34,16 @@
       </div>
       <div class="forum-post-body">
          {{ post.html|safe }}
-         {% if post.user.user_profile.signature_html %}
-            &mdash;{{ post.user.user_profile.signature_html|safe }}
+         {% if post.user.profile.signature_html %}
+            &mdash;{{ post.user.profile.signature_html|safe }}
          {% endif %}
          {% if post.has_been_edited %}
          <p class="small quiet">Last edited: {{ post.update_date|date:"M d, Y H:i:s" }}</p>
          {% endif %}
       </div>
-      {% if post.attach_list %}
+      {% if post.attachments.all %}
       <div>
-         {% for item in post.attach_list %}
+         {% for item in post.attachments.all %}
          <div class="forum-attachment">{{ item.html|safe }}</div>
          {% endfor %}
       </div>
@@ -60,7 +60,7 @@
       {% if can_moderate %}
       <a href="#" class="post-delete" id="dp-{{ post.id }}"
          title="Delete this post"><img src="{{ STATIC_URL }}icons/cross.png" alt="Delete post" /></a>
-         {% if post.user != user and post.user.user_profile.is_stranger %}
+         {% if post.user != user and post.user.profile.is_stranger %}
          <br />
          <span class="quiet">Stranger options:</span>
          <a href="{% url 'forums-stranger' post.id %}" title="This stranger seems legitimate">
--- a/sg101/templates/membermap/markdown.html	Fri May 23 15:39:14 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-{% load markup %}
-{% load smiley_tags %}
-{% load bio_tags %}
-{% avatar user 0 "left" %}{% profile_link user.username %}:<br />{{ msg|safe }}
--- a/shoutbox/models.py	Fri May 23 15:39:14 2014 -0500
+++ b/shoutbox/models.py	Fri May 23 21:52:41 2014 -0500
@@ -31,7 +31,7 @@
     def save(self, *args, **kwargs):
         if not self.id:
             self.shout_date = datetime.datetime.now()
-        self.html = urlize(smilify_html(escape(self.shout)), trim_url_limit=15, 
+        self.html = urlize(smilify_html(escape(self.shout)), trim_url_limit=15,
                 nofollow=True)
         super(Shout, self).save(*args, **kwargs)
 
--- a/shoutbox/views.py	Fri May 23 15:39:14 2014 -0500
+++ b/shoutbox/views.py	Fri May 23 21:52:41 2014 -0500
@@ -54,7 +54,8 @@
 
 def view_history(request):
     """This view allows one to view the shoutbox history."""
-    paginator = DiggPaginator(Shout.objects.all().select_related(), 
+    qs = Shout.objects.select_related('user', 'user__profile')
+    paginator = DiggPaginator(qs,
             SHOUTS_PER_PAGE, body=5, tail=3, margin=3, padding=2)
     page = get_page(request.GET)
     try:
@@ -66,7 +67,7 @@
         'page': the_page,
         },
         context_instance = RequestContext(request))
-   
+
 
 shout_id_re = re.compile(r'shout-(\d+)')