fix: ring 'pocket' — fill gaps from deleted/unlisted products
get_ring_related_products walked exactly backward+forward positions in the ring and silently dropped entries whose IDs no longer resolved to visible products. Result: sparse offsets like [-2, -1, 1, 5, 28] visible in Up Next — a 'pocket' of live items in an otherwise stale ring slice. New behavior: fetch every ring product once (bulk query), keep only visibility==1, then walk further along the ring to collect the requested backward/forward VALID neighbors. Offsets are renumbered contiguously (-N..-1, 1..N). Pocket is filled by skipping past deleted/unlisted entries until we have the requested count or exhaust the ring. Ring traversal on the client (ringPosition + direction) uses ring indices directly and is unaffected — only the rendered Up Next sidebar slice is densified.
This commit is contained in:
parent
3470d747f3
commit
81a5de4ce1
1 changed files with 44 additions and 25 deletions
|
|
@ -760,6 +760,10 @@ def get_ring_related_products(product, ring, forward=42, backward=3):
|
|||
Returns a list of dicts: {"product": Product, "offset": int}
|
||||
where offset is negative for previous, positive for next.
|
||||
Falls back to get_related_products if product not in ring.
|
||||
|
||||
Walks past deleted or non-public ring entries to fill the requested
|
||||
backward/forward counts with contiguous offsets. Prevents "pocket"
|
||||
gaps where most neighbors in the raw ring are stale.
|
||||
"""
|
||||
product_id_str = str(product.id)
|
||||
if product_id_str not in ring:
|
||||
|
|
@ -768,34 +772,49 @@ def get_ring_related_products(product, ring, forward=42, backward=3):
|
|||
|
||||
idx = ring.index(product_id_str)
|
||||
ring_len = len(ring)
|
||||
if ring_len < 2:
|
||||
return []
|
||||
|
||||
# Cap forward to avoid overlap with backward items in circular ring
|
||||
max_forward = max(ring_len - 1 - backward, 0)
|
||||
forward = min(forward, max_forward)
|
||||
# Fetch every ring product in one query; keep only visibility==1.
|
||||
# Ring is built from public products, but items can become unlisted
|
||||
# or be deleted after the fact — skip those so Up Next stays a
|
||||
# dense list of valid discovery targets.
|
||||
products = get_products_by_ids(product.dbsession, list(set(ring)))
|
||||
product_map = {str(p.id): p for p in products if p.visibility == 1}
|
||||
|
||||
# Walk backward from current, collect up to `backward` valid neighbors
|
||||
# (nearest first). Then reverse so sidebar reads -N, ..., -1.
|
||||
backward_ids = []
|
||||
step = 0
|
||||
while len(backward_ids) < backward and step < ring_len - 1:
|
||||
step += 1
|
||||
pos = (idx - step + ring_len) % ring_len
|
||||
pid = ring[pos]
|
||||
if pid == product_id_str:
|
||||
break
|
||||
if pid in product_map:
|
||||
backward_ids.append(pid)
|
||||
backward_ids.reverse()
|
||||
|
||||
# Walk forward from current, collect up to `forward` valid neighbors.
|
||||
forward_ids = []
|
||||
step = 0
|
||||
while len(forward_ids) < forward and step < ring_len - 1:
|
||||
step += 1
|
||||
pos = (idx + step) % ring_len
|
||||
pid = ring[pos]
|
||||
if pid == product_id_str:
|
||||
break
|
||||
if pid in product_map:
|
||||
forward_ids.append(pid)
|
||||
|
||||
# Collect IDs with their offsets: negative=previous, positive=next
|
||||
items = []
|
||||
for i in range(backward, 0, -1):
|
||||
prev_idx = (idx - i + ring_len) % ring_len
|
||||
items.append((ring[prev_idx], -i))
|
||||
for i in range(1, min(forward + 1, ring_len)):
|
||||
next_idx = (idx + i) % ring_len
|
||||
items.append((ring[next_idx], i))
|
||||
|
||||
if not items:
|
||||
return []
|
||||
|
||||
all_ids = [pid for pid, _ in items]
|
||||
products = get_products_by_ids(product.dbsession, all_ids)
|
||||
if not products:
|
||||
return []
|
||||
|
||||
product_map = {str(p.id): p for p in products}
|
||||
return [
|
||||
{"product": product_map[pid], "offset": offset}
|
||||
for pid, offset in items
|
||||
if pid in product_map
|
||||
]
|
||||
backward_offset_start = -len(backward_ids)
|
||||
for i, pid in enumerate(backward_ids):
|
||||
items.append({"product": product_map[pid], "offset": backward_offset_start + i})
|
||||
for i, pid in enumerate(forward_ids):
|
||||
items.append({"product": product_map[pid], "offset": i + 1})
|
||||
return items
|
||||
|
||||
|
||||
def get_related_products(product, limit=8):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue