You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在类OLX应用中实现固定位置的精选与普通产品分页列表展示

如何在类OLX应用中实现固定位置的精选与普通产品分页列表展示

嘿,我来帮你梳理下怎么实现这个需求!从你描述的场景和给出的模型来看,核心是要让每一页的产品列表都优先展示最新添加的活跃精选产品,同时配合普通产品的正常分页逻辑,当翻页时如果当前页没有新的精选产品可用,就从之前的精选里补位,直到所有活跃精选产品都展示完毕。咱们一步步来实现:

一、先搞定活跃精选产品的筛选

首先,我们需要能准确获取当前处于有效期内的精选产品,并且按「最新添加」排序(符合你“主重新产品”的需求)。利用你已有的FeaturedProduct模型的is_active逻辑,我们可以写一个工具函数:

from django.utils import timezone

def get_active_featured_products():
    # 筛选出当前仍在有效期内的精选产品,按添加时间倒序(最新的排在最前面)
    return FeaturedProduct.objects.filter(
        end_time__gte=timezone.now()
    ).order_by('-start_time').select_related('product')

二、优化模型一致性(重要!)

你的Product模型有is_featured字段,同时FeaturedProduct是一对一关联产品,这两个状态需要保持一致,避免出现“产品已经不在精选列表但is_featured还是True”的情况。我们可以修改FeaturedProductsavedelete方法来自动同步:

class FeaturedProduct(BaseModel):
    # ... 你的现有字段 ...

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        # 保存精选记录时,自动把对应产品标记为精选
        self.product.is_featured = True
        self.product.save(update_fields=['is_featured'])

    def delete(self, *args, **kwargs):
        # 删除精选记录时,自动取消对应产品的精选标记
        self.product.is_featured = False
        self.product.save(update_fields=['is_featured'])
        super().delete(*args, **kwargs)

三、实现分页融合逻辑

假设我们设定每页展示12个产品,其中前3个是精选产品的固定位置。我们需要把精选产品和普通产品的分页逻辑结合起来,核心思路是:

  1. 普通产品按正常分页逻辑处理,但每页展示的数量要减去精选位的数量
  2. 精选产品按页取对应区间的内容,如果当前区间没有足够的精选产品,就从开头补位,直到填满精选位

以下是视图中的核心代码:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render

def product_list(request):
    # 获取搜索/筛选参数(根据你的实际需求调整)
    category_slug = request.GET.get('category')
    search_query = request.GET.get('q')

    # 1. 获取活跃精选产品列表
    featured_list = [fp.product for fp in get_active_featured_products()]
    total_featured = len(featured_list)

    # 2. 获取普通产品:已批准、非精选,且符合搜索/筛选条件
    normal_products = Product.objects.filter(
        status=Product.Status.APPROVED,
        is_featured=False
    )
    # 应用筛选条件
    if category_slug:
        normal_products = normal_products.filter(category__slug=category_slug)
    if search_query:
        normal_products = normal_products.filter(title__icontains=search_query)
    # 按最新添加排序(主重新产品)
    normal_products = normal_products.order_by('-created_at')  # 假设你的BaseModel有created_at字段

    # 3. 分页配置:每页总产品数12,其中3个是精选位
    PAGE_TOTAL_SIZE = 12
    FEATURED_SLOT_COUNT = 3
    # 普通产品每页展示数量 = 总页数 - 精选位数量
    normal_page_size = PAGE_TOTAL_SIZE - FEATURED_SLOT_COUNT

    # 处理普通产品的分页
    page_num = request.GET.get('page', 1)
    paginator = Paginator(normal_products, normal_page_size)

    try:
        normal_page = paginator.page(page_num)
    except PageNotAnInteger:
        normal_page = paginator.page(1)
    except EmptyPage:
        normal_page = paginator.page(paginator.num_pages)

    # 4. 组装当前页的产品列表:先填精选位,再填普通产品
    current_page_products = []

    # 计算当前页需要取的精选产品区间
    start_idx = (int(page_num) - 1) * FEATURED_SLOT_COUNT
    end_idx = start_idx + FEATURED_SLOT_COUNT

    # 填充精选位:如果有剩余精选就取新的,没有就从开头补
    for idx in range(start_idx, end_idx):
        if idx < total_featured:
            current_page_products.append(featured_list[idx])
        else:
            # 剩余位置用前面的精选产品补,直到填满或没有精选了
            remaining_slots = FEATURED_SLOT_COUNT - len(current_page_products)
            current_page_products.extend(featured_list[:remaining_slots])
            break

    # 添加当前页的普通产品
    current_page_products.extend(normal_page.object_list)

    # 5. 准备模板上下文
    context = {
        'products': current_page_products,
        'page_obj': normal_page,
        'total_featured': total_featured,
        'featured_slot_count': FEATURED_SLOT_COUNT,
        # 保留搜索/筛选参数,用于分页导航
        'current_category': category_slug,
        'current_query': search_query,
    }

    return render(request, 'product/product_list.html', context)

四、模板中区分展示样式

在模板里,我们可以给精选产品加上特殊样式,同时保留正常的分页导航:

{% for product in products %}
    {% if forloop.counter <= featured_slot_count and forloop.counter <= total_featured %}
        <!-- 精选产品的特殊样式 -->
        <div class="product-card featured">
            <div class="featured-badge">精选推荐</div>
            <h3>{{ product.title }}</h3>
            <!-- 产品其他信息:图片、价格、位置等 -->
        </div>
    {% else %}
        <!-- 普通产品样式 -->
        <div class="product-card">
            <h3>{{ product.title }}</h3>
            <!-- 产品其他信息 -->
        </div>
    {% endif %}
{% endfor %}

<!-- 分页导航栏 -->
<div class="pagination">
    {% if page_obj.has_previous %}
        <a href="?page={{ page_obj.previous_page_number }}
            {% if current_query %}&q={{ current_query }}{% endif %}
            {% if current_category %}&category={{ current_category }}{% endif %}">
            上一页
        </a>
    {% endif %}
    <span>第 {{ page_obj.number }} 页 / 共 {{ page_obj.paginator.num_pages }} 页</span>
    {% if page_obj.has_next %}
        <a href="?page={{ page_obj.next_page_number }}
            {% if current_query %}&q={{ current_query }}{% endif %}
            {% if current_category %}&category={{ current_category }}{% endif %}">
            下一页
        </a>
    {% endif %}
</div>

一些额外的细节处理

  • 如果没有活跃的精选产品,模板会自动跳过精选样式,直接展示普通产品分页
  • 如果普通产品数量为0,页面会只展示精选产品(如果有的话)
  • 分页导航会保留搜索和筛选参数,确保翻页后筛选条件不变

这样配置后,就能实现你想要的效果:每一页都优先展示最新的精选产品,翻页时如果没有新的精选产品,就用之前的精选补位,直到所有精选都展示完毕,同时普通产品正常分页,全程以新添加的产品为核心~

备注:内容来源于stack exchange,提问作者Nodirkhuja Khamitov

火山引擎 最新活动