Martelius
Martelius

Reputation: 41

Django filtering database items

I am trying to build a project where I have a DB with toys where there are brands, each brand have products, the products have variety of sizes and sizes have colors. What I want to achieve is to have a home page with filtered the brands which I manage to achieve with the views.py below:

def Index(request):
    toys = Toys.objects.values('brand').distinct().order_by('brand')
    context = {'index': toys }
    return render(request, 'index.html', context)

with models.py

class Toys(models.Model):
    brand= models.CharField(max_length=255)
    product = models.CharField(max_length=255)
    size = models.CharField(max_length=255)
    color = models.CharField(max_length=255)
    

Now on the main page I have a list with all the different brans, what I'm trying to do is when I click on any Brand for the home page to redirect me to a result page with list of the Brand's products, product will lead to all available sizes and so on. How to implement that in the views?

Upvotes: 0

Views: 141

Answers (1)

Dr. Red
Dr. Red

Reputation: 141

Many approaches are possible. If you do not wish to have better functionality (e.g. all toys from brand 'X' are deleted when the brand is deleted from database), you could do the following.

Write a view function for each "level" of your listing. In the context dictionary, index contains the query result, listing is a heading to be displayed and level is a variable to select how the link is constructed in the template.

from django.shortcuts import render
from toyapp.models import Toys

def Index(request):
    toys = Toys.objects.values('brand').distinct().order_by('brand')
    context = { 'index': toys,
                'listing': 'Toy brands:',
                'level': 'brands',
    }
    return render(request,'toyapp/index.html', context)

def brandview(request, slug):
    toys = Toys.objects.filter(brand=slug).order_by('product')
    context = {'level': 'products',
                'index': toys,
                'listing': 'Products from brand ' + slug,
    }
    return render(request,'toyapp/index.html', context)

def productview(request, slug1, slug2):
    toys_set = Toys.objects.filter(brand=slug1)
    toys = toys_set.filter(product=slug2).order_by('size')
    context = {'level': 'sizes',
                'index': toys,
                'listing': 'Sizes for product ' + slug2 + ' from brand ' + slug1
    }
    return render(request,'toyapp/index.html', context)

def sizeview(request, slug1, slug2, slug3):
    toys_set = Toys.objects.filter(brand=slug1)
    toys = toys_set.filter(product=slug2).order_by('size')
    context = {'level': 'colors',
                'index': toys,
                'listing': 'Colors for size ' + slug3 + ' products ' + slug2 + ' from brand ' + slug1
    }
    return render(request,'toyapp/index.html', context)

The template index.html is quite simple with a {% for %} loop to go through items and {% if %} tags to select what kind of a link to create and what text to display.

<!DOCTYPE html>
<body>
  <h2>{{ listing }}</h2>
  {% for item in index %}
    <li>
      {% if level == 'brands' %}
        <a href="{% url 'brandview' slug=item.brand %}" >{{item.brand}}</a>
      {% elif level == 'products' %}
        <a href="{% url 'productview' slug1=item.brand slug2=item.product %}" >{{item.product}}</a>
      {% elif level == 'sizes' %}
        <a href="{% url 'sizeview' slug1=item.brand slug2=item.product slug3=item.size %}" >{{item.size}}</a>
      {% elif level == 'colors' %}
        {{item.color}}
      {% endif %}
    </li>
  {% endfor %}
</body>

Finally, you need to write urls.py with urlpatterns that parses the HTTP request address and passes the arguments to the view.

from django.urls import path, include
from . import views
urlpatterns = [
    path('', views.Index, name='index'),
    path('<slug:slug>', views.brandview, name='brandview'),
    path('<slug:slug1>,<slug:slug2>', views.productview, name='productview'),
    path('<slug:slug1>,<slug:slug2>,<slug:slug3>', views.sizeview, name='sizeview'),
]

Upvotes: 1

Related Questions