Skip to content

Instantly share code, notes, and snippets.

@skliarpawlo
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skliarpawlo/1d79c0dd1056778d2c09 to your computer and use it in GitHub Desktop.
Save skliarpawlo/1d79c0dd1056778d2c09 to your computer and use it in GitHub Desktop.
layout of items sequentially taking (slot types:item type) mapping into account
from blog.const import NEWS_TILE_TYPE
from catalog.const import PRODUCTS_TILE_TYPE, FEATURED_PRODUCTS_TILE_TYPE
from index.services.query import get_tiles_qs
PER_PAGE = 6
# list of layouts 'id's
LAYOUTS_PATTERN = [0, 3, 1]
# all tile type should be listed here, used for iterating
TILE_TYPES = (
NEWS_TILE_TYPE, PRODUCTS_TILE_TYPE, FEATURED_PRODUCTS_TILE_TYPE
)
LAYOUTS_TO_ORDER = {
0: [ # exact order of tile types to be provided for layout to be rendered properly
PRODUCTS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE,
],
1: [
NEWS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE, PRODUCTS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE,
],
2: [
NEWS_TILE_TYPE, PRODUCTS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE,
],
3: [
FEATURED_PRODUCTS_TILE_TYPE,
],
4: [ # exact order of tile types to be provided for layout to be rendered properly
NEWS_TILE_TYPE, NEWS_TILE_TYPE, PRODUCTS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE, NEWS_TILE_TYPE,
],
}
# use tile of other type if not enough
FALLBACK = {
# need fallback # this is fallback
PRODUCTS_TILE_TYPE: NEWS_TILE_TYPE,
}
def get_mode_by_page(page):
""" Returns layout which to render on specified page. 1 layout for 1 page
"""
return LAYOUTS_PATTERN[page % len(LAYOUTS_PATTERN)]
def _get_paged_tiles_by_type(tile_type, page=0, as_fallback=False):
""" if as_fallback == False: return list of tiles of type `tile_type` needed for specified page
if as_fallback == True: return list of tiles that should be used as fallback for other types
"""
# count how much tiles of this type already used (not as fallback) on
# previous pages
start_index = 0
for p in range(page):
start_index += LAYOUTS_TO_ORDER[get_mode_by_page(p)].count(tile_type)
# calculate how much tiles of this type are used (as fallback) on previous
# pages
dx = 0
for _from, _to in FALLBACK.items():
if _to == tile_type:
fallback_counts = _fallback_tiles_count_needed_for_type(
_from,
page)
dx += sum(fallback_counts)
start_index += sum(fallback_counts[:-1])
if not as_fallback:
start_index += dx
on_page_count = LAYOUTS_TO_ORDER[
get_mode_by_page(page)].count(tile_type)
return get_tiles_qs().filter(tile_type_id=tile_type)[
start_index:start_index + on_page_count]
else:
return get_tiles_qs().filter(tile_type_id=tile_type)[
start_index:start_index + dx]
def _fallback_tiles_count_needed_for_type(tile_type, page=0):
""" Calculates how much tiles of type `tile_type` are needed on each page from 0 to `page`,
Returns array of integers
"""
res = []
total_count = get_tiles_qs().filter(
tile_type__identifier=tile_type).count()
start_index = 0
for p in range(page + 1):
cnt = LAYOUTS_TO_ORDER[get_mode_by_page(p)].count(tile_type)
if start_index + cnt <= total_count:
res.append(0)
elif start_index < total_count < start_index + cnt:
res.append(cnt - (total_count - start_index))
else:
res.append(cnt)
start_index += cnt
return res
def get_tiles_for_page(page, full_only=False):
""" Main function return tiles needed for page `page`
"""
order = LAYOUTS_TO_ORDER[get_mode_by_page(page)]
tiles = {}
for tile_type in TILE_TYPES:
tiles[tile_type] = list(_get_paged_tiles_by_type(tile_type, page))
if tile_type in FALLBACK:
tiles[tile_type].extend(
list(
_get_paged_tiles_by_type(
FALLBACK[tile_type],
page,
as_fallback=True))
)
candidates = []
for place in order:
# if not enough tile of some type - cannot return proper result, so
# exit
if full_only and len(tiles[place]) == 0:
return []
if len(tiles[place]) > 0:
candidates.append(
tiles[place].pop(0)
)
# hack for date ordering
news_tiles = filter(
lambda item: item.tile_type_id == NEWS_TILE_TYPE,
candidates)
news_tiles = sorted(news_tiles, key=lambda item: item.online_date)
res = []
for tile_content in candidates:
if tile_content.tile_type_id == NEWS_TILE_TYPE:
res.append(news_tiles.pop())
else:
res.append(tile_content)
res = candidates
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment