14. Displaying product size based on color selected

To dynamically display available product sizes based on the selected color, we will implement a solution that appends the color identifier to the product URL. This approach ensures that each color variant is accessed through a unique URL.

We will integrate the id_color variable as a parameter within the view_product function, initializing it with a default value of None. It is important to note that the parameters passed to the functions are derived from the URL components.

views.py
def view_product(request, product_id, id_color = None) :

Next, we will define a new path in the urls.py file to accommodate the URL that includes the color ID parameter. This will ensure the routing system correctly handles URLs containing the color identifier.

store\urls.py
    path('product/<int:product_id>', view_product, name="view_product"),
    path('product/<int:product_id>/<int:id_color>', view_product, name="view_product"),

To simplify the logic, we will modify the view_product function by initially setting the has_stock condition to False and initializing the sizes and colors sets as empty. This approach will allow us to eliminate the else statements at the end of the function, saving lines.

views.py
def view_product(request, product_id, id_color = None) :
    has_stock = False
    sizes = {}
    colors = {} #? needs to be declared

To display the available sizes for each product based on the selected color, we will enhance the logic within the view_product function. Specifically, we will add a condition inside the stock check to filter the products by the selected color. If a color is specified, the function will query the database using the color__id attribute, which retrieves the color ID created automatically from the Color class. This filtered query will then populate a set with all available sizes for the specified product color.

views.py
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 :
            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

Adding the sizesvariable to the context dictionary:

context = {'product': product, 'item_stock': item_stock, "has_stock" : has_stock, "colors" : colors, "sizes" : sizes}

Within the view_product.html template, we will remove the display of color names and make the color icons clickable. These clickable icons will direct the user to the URLs of the specific color IDs, which will in turn display the available sizes for that color.

view_product.html
<a href = "{% url 'view_product' product.id color.id %}"> <!--passing the url of 'view_product' determined in the name parameter of the urls.py, followed by the product.id and the color.id -->
    <i class="fa-solid fa-circle" style="color: {{ color.code }}"></i> <!--False positive, html doesnt recognize the django format but it is correct -->
</a>
{% endfor %}


{% if sizes %}

<p>Select the size:</p>

{% for size in sizes %}

<button>{{ size }}</button>

{% endfor %}

{% endif %}
Displaying the filtered sizes

Lastly, we will just display which color is being selected

Initializing a new variable selected_color_name

views.py
def view_product(request, product_id, id_color = None) :
    has_stock = False
    sizes = {}
    colors = {} #? needs to be declared
    selected_color_name = None

Obtaining the selected color name using its id

views.py
if id_color :
            color = Color.objects.get(id = id_color) #? gets the color object from the Color class
            selected_color_name = color.name

Adding selected_color_name to the context dictionary

context = {'product': product, 'item_stock': item_stock, "has_stock" : has_stock, "colors" : colors, "sizes" : sizes, "selected_color_name" : selected_color_name}

Displaying it before the color icon for loop

view_product.html
{% if selected_color_name %}

Color: {{ selected_color_name }}

{% endif %}

{% for color in colors %}
Now the sizes AND the color name are properly displayed when selecting a color icon.

Last updated