Last active
August 29, 2015 14:18
-
-
Save skliarpawlo/1d79c0dd1056778d2c09 to your computer and use it in GitHub Desktop.
layout of items sequentially taking (slot types:item type) mapping into account
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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