Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 17 additions & 23 deletions forum/backends/mysql/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db.models import F
from django.db import models
from django.db.models import QuerySet
from django.utils import timezone
Expand Down Expand Up @@ -437,40 +438,33 @@ def get_sort_key(self) -> str:
def get_list(**kwargs: Any) -> list[dict[str, Any]]:
"""
Retrieves a list of all comments in the database based on provided filters.

Args:
kwargs: The filter arguments.

Returns:
A list of comments.
Optimized with select_related and DB-level sorting/pagination.
"""

sort = kwargs.pop("sort", None)
resp_skip = kwargs.pop("resp_skip", 0)
resp_limit = kwargs.pop("resp_limit", None)
comments = Comment.objects.filter(**kwargs)
result = []

# select_related eliminates FK queries in to_dict()
comments = Comment.objects.filter(**kwargs).select_related(
"author", "parent", "comment_thread", "deleted_by"
)

# DB-level sorting instead of Python sorted()
if sort:
if sort == 1:
result = sorted(
comments, key=lambda x: (x.sort_key is None, x.sort_key or "")
)
comments = comments.order_by(F("sort_key").asc(nulls_last=True))
elif sort == -1:
result = sorted(
comments,
key=lambda x: (x.sort_key is None, x.sort_key or ""),
reverse=True,
)

paginated_comments = result or list(comments)
comments = comments.order_by(F("sort_key").desc(nulls_last=True))

# Apply pagination if resp_limit is provided
# DB-level pagination instead of loading all then slicing
if resp_limit is not None:
resp_end = resp_skip + resp_limit
paginated_comments = result[resp_skip:resp_end]
elif resp_skip: # If resp_limit is None but resp_skip is provided
paginated_comments = result[resp_skip:]
comments = comments[resp_skip:resp_end]
elif resp_skip:
comments = comments[resp_skip:]

return [content.to_dict() for content in paginated_comments]
return [content.to_dict() for content in comments]

@staticmethod
def get_list_total_count(**kwargs: Any) -> int:
Expand Down
12 changes: 1 addition & 11 deletions forum/serializers/comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,11 @@ def get_children(self, obj: Any) -> list[dict[str, Any]]:
return list(serializer.data)

def to_representation(self, instance: Any) -> dict[str, Any]:
"""Return comment representation."""
comment = super().to_representation(instance)
comment.pop("historical_abuse_flaggers")
if comment["parent_id"] == "None":
comment["parent_id"] = None

thread = self.backend.get_thread(comment["thread_id"])
comment_from_db = self.backend.get_comment(comment["id"])
if (
not comment["endorsed"]
and comment_from_db
and "endorsement" not in comment_from_db
and thread
and thread["thread_type"] == "question"
):
comment.pop("endorsement", None)
return comment

def create(self, validated_data: dict[str, Any]) -> Any:
Expand Down
Loading