Проект - площадка для объявлений. В ленте должны отображаются объявления с каруселью фотографий, но карусель корректно срабатывает только 1 раз

Первое объявление выводит фотографии корректно, дальше фотографии не выводятся вообще

views.py Тут список photos наполняться корректно, там есть фотографии всех объявлений

def index(request):
    media = Media.objects.all()
    photos = []
    ads, cats, _ = get_data_from_db()
    for ad in ads:
        for photo in media:
            if photo.ad.id == ad.id:
                photos.append(photo)
    page_obj = get_pagination(request, ads)

    context = {
        'title': 'All ads:',
        'cats': cats,
        'page_obj': page_obj,
        'photos': photos,

    }
    return render(request, 'main/index.html', context=context)

часть index.html отвечающая за вывод обьявления (в base.html подключен js для работы карусели)

<div class="album py-5 bg-light">
    <div class="container">
        <div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
                {% if page_obj %}
                    {% for el in page_obj %}
            <div class="col">
            <a href="{{ el.get_absolute_url }}" class="text-dark text-decoration-none">
            <div class="card shadow-sm">
                <div class="row justify-content-center py-2">
                    <div>
                    <div id="post_{{ el.id }}" class="carousel slide" data-bs-ride="carousel" data-bs-interval="false">
                        <div class="carousel-indicators">
                            {% for media in photos %}
                            {% if media.ad.id == el.id  %}
                                <button type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide-to="{{ forloop.counter0 }}"
                                    {% if forloop.first %} class="active" aria-current="true"{% endif %} aria-label="Slide {{ forloop.counter }}">
                                </button>
                            {% endif %}
                            {% endfor %}
                        </div>
                        <div class="carousel-inner">
                            {% for media in photos %}
                            {% if media.ad.id == el.id  %}
                                <div class="carousel-item {% if forloop.first %}active{% endif %}" align="center">
                                <img src="http://127.0.0.1:8080{{ media.media.url }} " height="325" width="400" border="8" alt="{{el.title}}">
                                </div>
                            {% endif %}
                            {% endfor %}
                        </div>
                        <button class="carousel-control-prev" type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide="prev">
                            <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                            <span class="visually-hidden">Previous</span>
                        </button>
                        <button class="carousel-control-next" type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide="next">
                            <span class="carousel-control-next-icon" aria-hidden="true"></span>
                            <span class="visually-hidden">Next</span>
                        </button>
                    </div>

                     </div>
                </div>
                <div class="card-body">
                    <h3>{{ el.title }}</h3>
                    <h5>{{ el.price }} $</h5>
                    <p>{{ el.ad|linebreaks|truncatewords:4 }}</p>
                <div class="d-flex justify-content-between align-items-center">
                    <small class="text-muted">Date: {{ el.time_create|date:"d-m-Y H:i" }}</small>

                    {% for cat in cats %}
                        {% if cat.id == el.cat.id %}
                            <small class="text-muted"><a href="{{ cat.get_absolute_url }}" class="text-dark">Category: {{ el.cat }}</a></small>
                        {% endif %}
                    {% endfor %}
                </div>
                </div>
            </div>
            </a>
            </div>
                    {% endfor %}
                {% else %}
                    <p>There is no ads!</p>
                {% endif %}
        </div>
    </div>
</div>

{% if page_obj.has_other_pages %}
    <span class="step-links">
        <ul class="nav justify-content-center pb-3 mb-3">
            {% if page_obj.has_previous %}
                <a class="page-link text-muted" href="?page={{ page_obj.previous_page_number }}">&lt;</a>
            {% endif %}
            {% for p in page_obj.paginator.page_range %}
            {% if page_obj.number == p %}
                <li class="page-item active">
                    <a class="page-link" href="?page={{ p }}">{{ p }}</a>
                </li>
            {% elif p >= page_obj.number|add:-2 and p <= page_obj.number|add:2 %}
                <li class="page-item">
                    <a class="page-link text-muted" href="?page={{ p }}">{{ p }}</a>
                </li>
            {% endif %}
            {% endfor %}
            {% if page_obj.has_next %}
                <a class="page-link text-muted" href="?page={{ page_obj.next_page_number }}">&gt;</a>
            {% endif %}
        </ul>
    </span>
{% endif %}

Выглядит вот так

Это вариант исправления в темплейте:

В диве carousel-indicators вы запускаете два цикла по одним и тем же данным, но они не обязательно синхронны между собой, измените это формирование цикла, и проверьте рендер темплэйта.

Например:

<div id="post_{{ el.id }}" class="carousel slide" data-bs-ride="carousel" data-bs-interval="false">
    {% for media in photos %}
    {% if media.ad.id == el.id  %}
    <div class="carousel-indicators">
        <button type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide-to="{{ forloop.counter0 }}"
                {% if forloop.first %} class="active" aria-current="true"{% endif %} aria-label="Slide {{ forloop.counter }}">
        </button>
    </div>
    <div class="carousel-inner">
        <div class="carousel-item {% if forloop.first %}active{% endif %}" align="center">
            <img src="http://127.0.0.1:8080{{ media.media.url }} " height="325" width="400" border="8" alt="{{el.title}}">
        </div>
    </div>
    {% endif %}
    {% endfor %}
    <button class="carousel-control-prev" type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
    </button>
    <button class="carousel-control-next" type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
    </button>
</div>

Но лучше тщательнее готовить queryset, что бы как можно меньше делать проверок в темплэйте.

Пример views.py:

from dataclasses import dataclass
# Здесь делаю подготовку данных используя - dataclass
# это позволит мне ускорить рендер страницы и меньше данных
# перебирать в темплэйте

@dataclass
class AdCtx:
    id: int
    photos: list

def index(request):
    media = Media.objects.all()
    
    # тут соберу объекты для контекста
    ads_ctx = list()  
    
    ads, cats, _ = get_data_from_db()
    for ad in ads:
        ad_photos = []
        for photo in media:
            if photo.ad.id == ad.id:
                
                # каждый набор фото принадлежит только одному ad.id
                ad_photos.append(photo) 
                
        # тут наполняю датакласс
        ad_ctx = AdCtx(ad.id, ad_photos)  
        # тут дсе датаклассы собираю в list
        ads_ctx.append(ad_ctx)
          
    # В пагинатор отправляю данные собранные на датаклассе       
    page_obj = get_pagination(request, ads_ctx)  

    # В контекст идет комплект данных: список ads разделенный 
    # на объект ad.id и набор его photo
    # Это позволяет в темплэйте не делать сравнений и проверок
    context = {
        'title': 'All ads:',
        'cats': cats,
        'page_obj': page_obj,
    }
    return render(request, 'main/index.html', context=context)

Пример templates:

<div class="album py-5 bg-light">
    <div class="container">
        <div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
            {% if page_obj|length > 0 %}
            {% for el in page_obj %}
            <div class="col">
            <a href="{{ el.get_absolute_url }}" class="text-dark text-decoration-none">
            <div class="card shadow-sm">
                <div class="row justify-content-center py-2">
                    <div>
                        <div id="post_{{ el.id }}" class="carousel slide" data-bs-ride="carousel" data-bs-interval="false">
                            {% for media in el.photos %}
                            <div class="carousel-indicators">
                                <button type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide-to="{{ forloop.counter0 }}"
                                    {% if forloop.first %} class="active" aria-current="true"{% endif %} aria-label="Slide {{ forloop.counter }}">
                                </button>
                            </div>
                            <div class="carousel-inner">
                                <div class="carousel-item {% if forloop.first %}active{% endif %}" align="center">
                                <img src="http://127.0.0.1:8080{{ media.media.url }} " height="325" width="400" border="8" alt="{{el.title}}">
                                </div>
                            </div>
                            {% endfor %}
                            <button class="carousel-control-prev" type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide="prev">
                                <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                                <span class="visually-hidden">Previous</span>
                            </button>
                            <button class="carousel-control-next" type="button" data-bs-target="#post_{{ el.id }}" data-bs-slide="next">
                                <span class="carousel-control-next-icon" aria-hidden="true"></span>
                                <span class="visually-hidden">Next</span>
                            </button>
                        </div>
                    </div>
                </div>
                <div class="card-body">
                    <h3>{{ el.title }}</h3>
                    <h5>{{ el.price }} $</h5>
                    <p>{{ el.ad|linebreaks|truncatewords:4 }}</p>
                <div class="d-flex justify-content-between align-items-center">
                    <small class="text-muted">Date: {{ el.time_create|date:"d-m-Y H:i" }}</small>
                    {% for cat in cats %}
                        {% if cat.id == el.cat.id %}
                            <small class="text-muted"><a href="{{ cat.get_absolute_url }}" class="text-dark">Category: {{ el.cat }}</a></small>
                        {% endif %}
                    {% endfor %}
                </div>
                </div>
            </div>
            </a>
            </div>
            {% endfor %}
            {% else %}
                <p>There is no ads!</p>
             {% endif %}
        </div>
    </div>
</div>

Конечно этот код надо проверять на живых данных, я не проверял все выводы данных в темплэйте :)

Вернуться на верх