Homepage: Preload review information in queries

This commit is contained in:
rubenwardy 2022-11-18 21:15:46 +00:00
parent b72244398b
commit db8574ffe3
8 changed files with 24 additions and 13 deletions

@ -3,7 +3,7 @@ from flask import Blueprint, render_template, redirect
bp = Blueprint("homepage", __name__) bp = Blueprint("homepage", __name__)
from app.models import * from app.models import *
from sqlalchemy.orm import joinedload, subqueryload from sqlalchemy.orm import joinedload, subqueryload, contains_eager
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
@ -45,6 +45,13 @@ def home():
joinedload(Package.license), joinedload(Package.license),
joinedload(Package.media_license)) joinedload(Package.media_license))
def review_load(query):
return query.options(
joinedload(PackageReview.author),
joinedload(PackageReview.thread).joinedload(Thread.first_reply),
joinedload(PackageReview.package).joinedload(Package.author).load_only(User.username, User.display_name),
joinedload(PackageReview.package).load_only(Package.title, Package.name).subqueryload(Package.main_screenshot))
query = Package.query.filter_by(state=PackageState.APPROVED) query = Package.query.filter_by(state=PackageState.APPROVED)
count = query.count() count = query.count()
@ -64,7 +71,7 @@ def home():
.limit(20)).all() .limit(20)).all()
updated = updated[:4] updated = updated[:4]
reviews = PackageReview.query.filter_by(recommends=True).order_by(db.desc(PackageReview.created_at)).limit(5).all() reviews = review_load(PackageReview.query.filter_by(recommends=True).order_by(db.desc(PackageReview.created_at))).limit(5).all()
downloads_result = db.session.query(func.sum(Package.downloads)).one_or_none() downloads_result = db.session.query(func.sum(Package.downloads)).one_or_none()
downloads = 0 if not downloads_result or not downloads_result[0] else downloads_result[0] downloads = 0 if not downloads_result or not downloads_result[0] else downloads_result[0]

@ -66,7 +66,7 @@ def review(package):
if request.method == "GET" and review: if request.method == "GET" and review:
form.title.data = review.thread.title form.title.data = review.thread.title
form.recommends.data = "yes" if review.recommends else "no" form.recommends.data = "yes" if review.recommends else "no"
form.comment.data = review.thread.replies[0].comment form.comment.data = review.thread.first_reply.comment
# Validate and submit # Validate and submit
elif can_review and form.validate_on_submit(): elif can_review and form.validate_on_submit():
@ -99,7 +99,7 @@ def review(package):
thread.replies.append(reply) thread.replies.append(reply)
else: else:
reply = thread.replies[0] reply = thread.first_reply
reply.comment = form.comment.data reply.comment = form.comment.data
thread.title = form.title.data thread.title = form.title.data

@ -154,7 +154,7 @@ def delete_reply(id):
if reply is None or reply.thread != thread: if reply is None or reply.thread != thread:
abort(404) abort(404)
if thread.replies[0] == reply: if thread.first_reply == reply:
flash(gettext("Cannot delete thread opening post!"), "danger") flash(gettext("Cannot delete thread opening post!"), "danger")
return redirect(thread.getViewURL()) return redirect(thread.getViewURL())

@ -55,8 +55,12 @@ class Thread(db.Model):
watchers = db.relationship("User", secondary=watchers, backref="watching") watchers = db.relationship("User", secondary=watchers, backref="watching")
first_reply = db.relationship("ThreadReply", uselist=False, foreign_keys="ThreadReply.thread_id",
lazy=True, order_by=db.asc("id"), viewonly=True,
primaryjoin="Thread.id==ThreadReply.thread_id")
def get_description(self): def get_description(self):
comment = self.replies[0].comment.replace("\r\n", " ").replace("\n", " ").replace(" ", " ") comment = self.first_reply.comment.replace("\r\n", " ").replace("\n", " ").replace(" ", " ")
if len(comment) > 100: if len(comment) > 100:
return comment[:97] + "..." return comment[:97] + "..."
else: else:
@ -156,7 +160,7 @@ class ThreadReply(db.Model):
return user.rank.atLeast(UserRank.NEW_MEMBER if user == self.author else UserRank.MODERATOR) and not self.thread.locked return user.rank.atLeast(UserRank.NEW_MEMBER if user == self.author else UserRank.MODERATOR) and not self.thread.locked
elif perm == Permission.DELETE_REPLY: elif perm == Permission.DELETE_REPLY:
return user.rank.atLeast(UserRank.MODERATOR) and self.thread.replies[0] != self return user.rank.atLeast(UserRank.MODERATOR) and self.thread.first_reply != self
else: else:
raise Exception("Permission {} is not related to threads".format(perm.name)) raise Exception("Permission {} is not related to threads".format(perm.name))
@ -201,7 +205,7 @@ class PackageReview(db.Model):
"unhelpful": neg, "unhelpful": neg,
}, },
"title": self.thread.title, "title": self.thread.title,
"comment": self.thread.replies[0].comment, "comment": self.thread.first_reply.comment,
} }
if include_package: if include_package:
ret["package"] = self.package.getAsDictionaryKey() ret["package"] = self.package.getAsDictionaryKey()

@ -38,7 +38,7 @@
{% endif %} {% endif %}
</div> </div>
{% if review.thread %} {% if review.thread %}
{% set reply = review.thread.replies[0] %} {% set reply = review.thread.first_reply %}
<div class="col pr-0"> <div class="col pr-0">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">

@ -53,7 +53,7 @@
</a> </a>
{% endif %} {% endif %}
{% if current_user == thread.author and thread.review and thread.replies[0] == r %} {% if current_user == thread.author and thread.review and thread.first_reply == r %}
<a class="float-right btn btn-primary btn-sm ml-2" <a class="float-right btn btn-primary btn-sm ml-2"
href="{{ thread.review.package.getURL('packages.review') }}"> href="{{ thread.review.package.getURL('packages.review') }}">
<i class="fas fa-pen"></i> <i class="fas fa-pen"></i>
@ -67,7 +67,7 @@
{{ r.comment | markdown }} {{ r.comment | markdown }}
{% if thread.replies[0] == r and thread.review %} {% if thread.first_reply == r and thread.review %}
{{ render_review_vote(thread.review, current_user, thread.getViewURL()) }} {{ render_review_vote(thread.review, current_user, thread.getViewURL()) }}
{% endif %} {% endif %}
</div> </div>

@ -10,7 +10,7 @@
<h3 class="card-header">{{ self.title() }}</h3> <h3 class="card-header">{{ self.title() }}</h3>
<div class="card-body markdown"> <div class="card-body markdown">
{{ thread.replies[0].comment | markdown }} {{ thread.first_reply.comment | markdown }}
</div> </div>
<div class="card-body"> <div class="card-body">
<p>{{ _("Deleting is permanent") }}</p> <p>{{ _("Deleting is permanent") }}</p>

@ -36,7 +36,7 @@
</span> </span>
{% endif %} {% endif %}
{% if r == r.thread.replies[0] %} {% if r == r.thread.first_reply %}
<a class="badge badge-primary" href="{{ r.thread.getViewURL() }}"> <a class="badge badge-primary" href="{{ r.thread.getViewURL() }}">
{{ r.thread.title }} {{ r.thread.title }}
</a> </a>