64. Similar products

Next, we will edit the view_product.html file to add a "Similar Products" section below the product details. A product will be considered similar if it shares the same category and type but is not the current product.

The similares section in the view_product.html file has been updated accordingly to display these similar products dynamically.

view_product.html
{% extends 'base.html' %}
{% load static %}

{% block body %}

<main class="principal principal--padding-b principal--gap">
    <section class="s-produto">
      <div class="s-produto__carrossel">
        <div class="s-produto__carrossel-itens">
          <div class="s-produto__carrossel-img">
            <img
              src="{{ product.image.url }}"
              alt="Imagem Carrossel 1"
            />
          </div>
          <div class="s-produto__carrossel-img" style="overflow: hidden;"> <!--Avoids the size itself of the image of getting big-->
            <img
              src="{{ product.image.url }}"
              alt="Imagem Carrossel 2"
              style="transform: scale(1.6);"
            />
          </div>
        </div>

        <div class="s-produto__carrossel-botoes">
          <div
            class="s-produto__carrossel-botao s-produto__carrossel-botao--selecionado"
          ></div>
          <div class="s-produto__carrossel-botao"></div>
          <div class="s-produto__carrossel-botao"></div>
          <div class="s-produto__carrossel-botao"></div>
          <div class="s-produto__carrossel-botao"></div>
        </div>
      </div>

      <div class="s-produto__informacoes">
        <div class="s-produto__breadcrumbs">
          <span><a href="{% url 'store' %}">Loja</a></span>
          <span><a href="{% url 'store' product.category.slug %}">{{ product.category.name }}</a></span>
          <span><a href="{% url 'store' %}{{ product.category.slug }}-{{ product.product_type.slug }}">{{ product.product_type.name }}</a></span>
          <span>
            <p>{{ product.name }}</p>
          </span>
        </div>

        <div class="s-produto__infos">
          <h1 class="s-produto__titulo">{{ product.name }}</h1>

          <p class="s-produto__preco">R$ {{ product.price }}</p>

          <div class="s-produto__cor">
            <p class="s-produto__cor-nome">Cor: <span>{{ selected_color.name }}</span></p>
            <div class="s-produto__cores">
                {% for color in colors %}
                <a
                href = "{% url 'view_product' product.id color.id %}"
                class="s-produto__cores-item"
                style="background-color: {{ color.code }};"
              ></a>
                {% endfor %}
            </div>
          </div>

          {% if has_stock %}
            {% if sizes %}
            <form method = "POST" action = "{% url 'add_to_cart' product.id %}">
                {% csrf_token %}
                <div class="s-produto__tamanho">
                    <div class="s-produto__tamanhos"> 
                        {% for size in sizes %}
                        <div class="menu__tamanho"> <!--Needs to have menu__tamanho class for the javascript-->
                            <div class="s-produto__tamanhos-item">{{ size }}</div>
                            <input class="menu__checkbox" type="radio" name="size" value="{{ size }}"> <!--menu__checkbox used in the produto.js-->
                        </div>
                        {% endfor %}
                    </div>
                </div>
                <input type="hidden" name="color" value="{{ selected_color.id }}">
                <button type="submit" class="s-produto__adicicionar">Adicionar à sacola</button>
            </form>
            {% endif %}
          {% else %}
          <h3>Item fora de estoque</h3>
          {% endif %}
        </div>


        <div class="s-produto__descricao">
          <p class="s-produto__descricao-titulo">Descrição do produto</p>
          <div class="s-produto__descricao-textos">
            <p>
              {{ product.description }}
            </p>
            <p>
              COMPOSIÇÃO <br />
                {{ product.composition }}
            </p>
            <p>
              CÓDIGO DO PRODUTO <br />
              Ref: <span>{{ product.id }}</span>
            </p>
          </div>
        </div>
      </div>
    </section>

    {% if similars %}
    <section class="similares">
      <h2 class="similares__titulo">
        Gostou desse produto? Veja itens similares
      </h2>

      <div class="similares__container">
        {% for similar in similars %}
        <a
          href="{% url 'view_product' similar.id %}"
          class="produto"
        >
          <div class="produto__imagem">
            <img
              src="{{ similar.image.url }}"
              alt="Imagem do Produto"
            />
          </div>
          <div class="produto__textos">
            <p class="produto__titulo">{{ similar.name }}</p>
            <div class="produto__preco">
              <p class="produto__avista">R$ {{ similar.price }}</p>
            </div>
          </div>
        </a>
        {% endfor %}
      </div>
    </section>
    {% endif %}
  </main>


  <script type="text/javascript" src="{% static 'js/produto.js' %}"></script>

{% endblock %}

Now, update the view_product function in the views.py file to include the queryset for similar products in the context. This allows the "Similar Products" section to render dynamically based on the defined criteria.

views.py
def view_product(request, product_id, id_color = None) :
    has_stock = False
    sizes = {}
    colors = {} #? needs to be declared
    selected_color = None
    product = Product.objects.get(id=product_id) #? id parameter is created automatically by django
    item_stock = ItemStock.objects.filter(product = product, quantity__gt = 0) #? gets the product that has more than 0 quantity (queryset lookup)
    if len(item_stock) > 0 : 
        has_stock = True #? necessary in order to do a if on the html. if the product is out of stock, will show "Out of Stock"
        colors = {item.color for item in item_stock} #? gets the colors of all products, uses sets '{}' to avoid duplicate colors
        if id_color :
            selected_color = Color.objects.get(id = id_color) #? gets the color object from the Color class
            item_stock = ItemStock.objects.filter(product = product, quantity__gt = 0, color__id = id_color) #? gets the color id  attribute from the Color class (that is automatically created)
            sizes = {item.size for item in item_stock} #? gets the sizes of all products
    similars = Product.objects.filter(category__id=product.category.id, product_type__id=product.product_type.id).exclude(id=product.id)[:4] #? gets all products that are not the same as the current one
    context = {'product': product, "has_stock" : has_stock, "colors" : colors, "sizes" : sizes, "selected_color" : selected_color, "similars" : similars}
    return render(request, 'view_product.html', context)

Note: The "Similar Products" section will display only the first four similar products, ensuring a concise and visually appealing layout.

Now, the list of four similar products is displayed correctly beneath the product view, as intended.

Last updated