Skip to content
Merged
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
78 changes: 62 additions & 16 deletions feed/helpers.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,11 @@
from rest_framework.views import APIView

from feed import constants
from feed.constants import SupportedModel, SupportedQuerySet, LIMIT_PAGINATION_CONSTANT
from feed.constants import (
SupportedModel,
SupportedQuerySet,
LIMIT_PAGINATION_CONSTANT
)
from feed.pagination import FeedPagination
from feed.serializers import FeedItemSerializer
from news.models import News
Expand All@@ -29,44 +33,86 @@ def paginate_serialize_feed(
result = []
pages_count = 0

offset = int(request.query_params.get("offset", 0))
if len(model_data) == 0:
return [], 0

offset = request.query_params.get("offset", 0)
request.query_params._mutable = True
request.query_params["offset"] = int(request.query_params["offset"])
offset_numbers = randomize_offset(offset, len(model_data.keys()))

for i in range(len(model_data.keys())):
request.query_params["offset"] = offset_numbers[i]
if isinstance(offset, str) and offset.isdigit():
offset = int(offset)
else:
offset = 0

request.query_params["offset"] = offset

models_counts = {
model_name: model_data[model_name].count() for model_name in model_data.keys()
}
offset_numbers = offset_distribution(offset, models_counts)

for model_name in model_data.keys():
request.query_params["offset"] = offset_numbers[model_name]

paginated_part: dict = paginate_serialize_feed_queryset(
model_data, paginator, request, list(model_data.keys())[i], view
model_data, paginator, request, model_name, models_counts[model_name], view
)

result += paginated_part["paginated_data"]
pages_count += paginated_part["page_count"]

shuffle(result)
limit = request.query_params.get("limit", LIMIT_PAGINATION_CONSTANT)

if limit == "":
limit = LIMIT_PAGINATION_CONSTANT
else:
limit = int(limit)

limit = int(request.query_params.get("limit", LIMIT_PAGINATION_CONSTANT))
shuffle(result)
return result[:limit], pages_count


def randomize_offset(offset: int, quantity_models: int) -> list[int]:
full_division = offset // quantity_models
extra_items = offset % quantity_models
def offset_distribution(offset: int, models_counts: dict) -> dict:
common_key_list = list(models_counts.keys())
quantity_of_models = len(list(models_counts.keys()))

full_division = offset // quantity_of_models
extra_items = offset % quantity_of_models

distributed_not_ready = {model_name: full_division for model_name in common_key_list}
distributed = dict(
sorted(distributed_not_ready.items(), key=lambda item: models_counts[item[0]])
)

last_key = common_key_list[-1]
distributed[last_key] += extra_items

pagination_numbers = [full_division] * quantity_models
pagination_numbers[-1] += extra_items
new_keys_list = list(distributed.keys())
for i, key in enumerate(
new_keys_list
): # распределяем переполненные значения от маленьких моделей к большим
offset_value = distributed[key]
model_count = models_counts[key]
if offset_value > model_count:
diff = offset_value - model_count
distributed[key] = model_count
if i + 1 < len(new_keys_list):
next_key = new_keys_list[i + 1]
distributed[next_key] += diff

return pagination_numbers
return distributed


def paginate_serialize_feed_queryset(
model_data: dict[SupportedQuerySet],
paginator: FeedPagination,
request: Request,
model: SupportedModel,
count: int,
view: APIView,
) -> dict:
paginated_info = paginator.custom_paginate_queryset(
model_data[model], request, view=view
model_data[model], request, count, view=view
)
paginated_data = paginated_info["queryset_ready"]
num_pages = paginated_info["count"]
Expand Down
6 changes: 3 additions & 3 deletions feed/pagination.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,13 @@ class FeedPagination(pagination.LimitOffsetPagination):
offset_query_param = "offset"

def custom_paginate_queryset(
self, queryset: SupportedQuerySet, request: Request, view=None
self, queryset: SupportedQuerySet, request: Request, count: int, view=None
) -> dict:
self.limit = self.get_limit(request)
if self.limit is None:
return None

self.count = self.get_count(queryset)
self.count = count
self.offset = self.get_offset(request)
self.request = request
if self.count > self.limit and self.template is not None:
Expand All@@ -25,7 +25,7 @@ def custom_paginate_queryset(
if self.count == 0 or self.offset > self.count:
return {"queryset_ready": [], "count": self.count}

queryset_ready = queryset[self.offset: self.offset + self.limit]
queryset_ready = queryset[self.offset: self.offset + self.limit]
return {
"queryset_ready": queryset_ready,
"count": self.count,
Expand Down