Просмотр исходного кода

Merge pull request #454 from flaskbb/kill-n-plus-1-queries

Kill n+1 queries in forum view
Peter Justin 7 лет назад
Родитель
Сommit
7f532d920b

+ 11 - 1
flaskbb/forum/models.py

@@ -1112,19 +1112,29 @@ class Forum(db.Model, CRUDMixin):
         :param per_page: How many topics per page should be shown
         """
         if user.is_authenticated:
+            # Now thats intersting - if i don't do the add_entity(Post)
+            # the n+1 still exists when trying to access 'topic.last_post'
+            # but without it it will fire another query.
+            # This way I don't have to use the last_post object when I
+            # iterate over the result set.
             topics = Topic.query.filter_by(forum_id=forum_id).\
                 outerjoin(TopicsRead,
                           db.and_(TopicsRead.topic_id == Topic.id,
                                   TopicsRead.user_id == user.id)).\
+                outerjoin(Post, Topic.last_post_id == Post.id).\
+                add_entity(Post).\
                 add_entity(TopicsRead).\
                 order_by(Topic.important.desc(), Topic.last_updated.desc()).\
                 paginate(page, per_page, True)
         else:
             topics = Topic.query.filter_by(forum_id=forum_id).\
+                outerjoin(Post, Topic.last_post_id == Post.id).\
+                add_entity(Post).\
                 order_by(Topic.important.desc(), Topic.last_updated.desc()).\
                 paginate(page, per_page, True)
 
-            topics.items = [(topic, None) for topic in topics.items]
+            topics.items = [(topic, last_post, None)
+                            for topic, last_post, in topics.items]
 
         return topics
 

+ 12 - 9
flaskbb/forum/views.py

@@ -570,15 +570,18 @@ class TopicTracker(MethodView):
 
     def get(self):
         page = request.args.get('page', 1, type=int)
-        topics = real(current_user).tracked_topics.outerjoin(
-            TopicsRead,
-            db.and_(
-                TopicsRead.topic_id == Topic.id,
-                TopicsRead.user_id == real(current_user).id
-            )
-        ).add_entity(TopicsRead).order_by(Topic.last_updated.desc()).paginate(
-            page, flaskbb_config['TOPICS_PER_PAGE'], True
-        )
+        topics = real(current_user).tracked_topics.\
+            outerjoin(
+                TopicsRead,
+                db.and_(
+                    TopicsRead.topic_id == Topic.id,
+                    TopicsRead.user_id == real(current_user).id
+                )).\
+            outerjoin(Post, Topic.last_post_id == Post.id).\
+            add_entity(Post).\
+            add_entity(TopicsRead).\
+            order_by(Topic.last_updated.desc()).\
+            paginate(page, flaskbb_config['TOPICS_PER_PAGE'], True)
 
         return render_template('forum/topictracker.html', topics=topics)
 

+ 5 - 5
flaskbb/templates/forum/edit_forum.html

@@ -35,7 +35,7 @@
                     <div class="col-md-1 col-sm-1 col-xs-2 topic-select-all"><input type="checkbox" name="rowtoggle" class="action-checkall" title="Select All"/></div>
                 </div>
 
-                {% for topic, topicread in topics.items %}
+                {% for topic, last_post, topicread in topics.items %}
                 <div class="row forum-row hover clearfix">
 
                     <div class="col-md-4 col-sm-4 col-xs-6 topic-info">
@@ -85,14 +85,14 @@
                     </div>
 
                     <div class="col-md-3 col-sm-3 col-xs-4 topic-last-post">
-                        <a href="{{ topic.last_post.url }}">{{ topic.last_post.date_created|time_since }}</a><br />
+                        <a href="{{ last_post.url }}">{{ last_post.date_created|time_since }}</a><br />
 
                         <div class="topic-author">
                             {% trans %}by{% endtrans %}
-                            {% if topic.last_post.user_id %}
-                            <a href="{{ topic.last_post.user.url }}">{{ topic.last_post.user.username }}</a>
+                            {% if last_post.user_id %}
+                            <a href="{{ last_post.user.url }}">{{ last_post.user.username }}</a>
                             {% else %}
-                            {{ topic.last_post.username }}
+                            {{ last_post.username }}
                             {% endif %}
                         </div>
                     </div>

+ 5 - 5
flaskbb/templates/forum/forum.html

@@ -52,7 +52,7 @@
                 <div class="col-md-3 col-sm-3 col-xs-4 topic-last-post">{% trans %}Last Post{% endtrans %}</div>
             </div>
 
-            {% for topic, topicread in topics.items %}
+            {% for topic, last_post, topicread in topics.items %}
             <div class="row forum-row hover clearfix">
 
                 <div class="col-md-5 col-sm-5 col-xs-8 topic-info">
@@ -109,14 +109,14 @@
                 </div>
 
                 <div class="col-md-3 col-sm-3 col-xs-4 topic-last-post">
-                    <a href="{{ topic.last_post.url }}">{{ topic.last_post.date_created|time_since }}</a><br />
+                    <a href="{{ last_post.url }}">{{ last_post.date_created|time_since }}</a><br />
 
                     <div class="topic-author">
                         {% trans %}by{% endtrans %}
-                        {% if topic.last_post.user_id %}
-                        <a href="{{ topic.last_post.user.url }}">{{ topic.last_post.user.username }}</a>
+                        {% if last_post.user_id %}
+                        <a href="{{ last_post.user.url }}">{{ last_post.user.username }}</a>
                         {% else %}
-                        {{ topic.last_post.username }}
+                        {{ last_post.username }}
                         {% endif %}
                     </div>
                 </div>

+ 5 - 5
flaskbb/templates/forum/topictracker.html

@@ -35,7 +35,7 @@
                     <div class="col-md-1 col-sm-1 col-xs-2 topic-select-all"><input type="checkbox" name="rowtoggle" class="action-checkall" title="Select All"/></div>
                 </div>
 
-                {% for topic, topicread in topics.items %}
+                {% for topic, last_post, topicread in topics.items %}
                 <div class="row forum-row hover clearfix">
 
                     <div class="col-md-4 col-sm-4 col-xs-6 topic-info">
@@ -85,14 +85,14 @@
                     </div>
 
                     <div class="col-md-3 col-sm-3 col-xs-4 topic-last-post">
-                        <a href="{{ topic.last_post.url }}">{{ topic.last_post.date_created|time_since }}</a><br />
+                        <a href="{{ last_post.url }}">{{ last_post.date_created|time_since }}</a><br />
 
                         <div class="topic-author">
                             {% trans %}by{% endtrans %}
-                            {% if topic.last_post.user_id %}
-                            <a href="{{ topic.last_post.user.url }}">{{ topic.last_post.user.username }}</a>
+                            {% if last_post.user_id %}
+                            <a href="{{ last_post.user.url }}">{{ last_post.user.username }}</a>
                             {% else %}
-                            {{ topic.last_post.username }}
+                            {{ last_post.username }}
                             {% endif %}
                         </div>
                     </div>

+ 3 - 3
flaskbb/utils/helpers.py

@@ -298,7 +298,7 @@ def topic_is_unread(topic, topicsread, user, forumsread=None):
         return False
 
     # check read_cutoff
-    if topic.last_post.date_created < read_cutoff:
+    if topic.last_updated < read_cutoff:
         return False
 
     # topicsread is none if the user has marked the forum as read
@@ -306,14 +306,14 @@ def topic_is_unread(topic, topicsread, user, forumsread=None):
     if topicsread is None:
         # user has cleared the forum - check if there is a new post
         if forumsread and forumsread.cleared is not None:
-            return forumsread.cleared < topic.last_post.date_created
+            return forumsread.cleared < topic.last_updated
 
         # user hasn't read the topic yet, or there is a new post since the user
         # has marked the forum as read
         return True
 
     # check if there is a new post since the user's last topic visit
-    return topicsread.last_read < topic.last_post.date_created
+    return topicsread.last_read < topic.last_updated
 
 
 def mark_online(user_id, guest=False):  # pragma: no cover