Home > OS >  facing problems with 'if' statement for Django templates and Django Models
facing problems with 'if' statement for Django templates and Django Models

Time:03-18

I have been working on a price comparison site but I am facing a problem when I try to write a if statement for different products so they show their own details rather than showing all detail fields in every product.

views.py

from django.shortcuts import render, get_object_or_404

from .models import Category, Product, Brand, Smartphone_detail

def index(request):
    products = Product.objects.all()
    return render(request, 'core/home.html', {'products': products})

def categories(request):
    return {
        'categories': Category.objects.all()
    }

def product_detail(request, slug):
    product = get_object_or_404(Product, slug=slug, in_stock=True)
    return render(request, 'core/products/detail.html', {'product': product})

def category_list(request, category_slug):
    category = get_object_or_404(Category, slug=category_slug)
    products = Product.objects.filter(category=category)
    return render(request, 'core/products/category.html', {'category': category, 'products': products})

models.py

from django.db import models
from django.urls import reverse
from django.db.models import Case, Value, When


class Category(models.Model):
    name = models.CharField(max_length=120, verbose_name='category name')
    slug = models.SlugField(max_length=150, verbose_name='category url')

    class Meta:
        verbose_name_plural = 'categories'

    def get_absolute_url(self):
        return reverse("core:category_list", args={self.slug})
    

    def __str__(self):
        return self.name


class Brand(models.Model):
    name = models.CharField(max_length=120, verbose_name='name of the brand')
    slug = models.SlugField(max_length=120, verbose_name='brand url')
    image = models.ImageField(upload_to='images/', verbose_name='brand image')
    description = models.TextField(verbose_name='brand moto or tagline')

    class Meta:
        verbose_name_plural = 'brands'

    def __str__(self):
        return self.name


class Smartphone_detail(models.Model):
    name = models.CharField(max_length=220, verbose_name=("product name"))
    brand = models.CharField(max_length=120, verbose_name=("product brand"))
    ram = models.IntegerField(verbose_name=("ram"))
    storage = models.IntegerField(verbose_name=("storage"))
    camera = models.CharField(verbose_name=("camera"), max_length=150)
    processor = models.CharField(verbose_name=("processor"), max_length=50)
    fingerprint = models.CharField(verbose_name=("figerprint"), max_length=50)
    battery = models.CharField(verbose_name=("battery capacity"), max_length=50)
    charger = models.CharField(verbose_name=("charger type and power"), max_length=150)
    charging_speed = models.CharField(verbose_name=("charging speed"), max_length=50)

    def __str__(self):
        return '{}'.format(self.name)


class Fashiondetail(models.Model):
    CHOICES = (
        ('XXS', '22'),
        ('XS', '24'),
        ('S', '26'),
        ('M', '28'),
        ('L', '30'),
        ('XL', '32'),
        ('XXL', '34'),
        ('XXXL', '36'),
    )
    name = models.CharField(max_length=220, verbose_name=("product name"))
    brand = models.CharField(max_length=120, verbose_name=("product brand"))
    size = models.CharField(max_length=250, choices = CHOICES)

    def __str__(self):
        return self.name

    
class Smartphone_accessory_detail(models.Model):
    TYPES = (
        ('Earphones'),
        ('Earbuds'),
        ('Headphones'),
        ('Smartwatch'),
        ('Fitness Bands'),
        ('Bluetooth Speakers'),
        ('Power Banks'),
    )
    name = models.CharField(max_length=220, verbose_name=("product name"))
    brand = models.CharField(max_length=120, verbose_name=("product brand"))
    type = models.CharField(max_length=120, verbose_name=('product type'), choices=TYPES)


class Product(models.Model):
    title = models.CharField(max_length=250, verbose_name='product name')
    slug = models.SlugField(max_length=300, verbose_name='product url')
    image = models.ImageField(upload_to='images/', verbose_name='product image')
    category = models.ManyToManyField(Category, blank=False, verbose_name='product category')
    brand = models.ManyToManyField(Brand, blank=True, verbose_name='brand name')
    price = models.DecimalField(max_digits=8,  decimal_places=2, default=000000.00, verbose_name='product price')
    in_stock = models.BooleanField(default=True, verbose_name='product availability')
    description = models.TextField(null=True, verbose_name='product description')
    smartphone_detail = models.OneToOneField(Smartphone_detail, on_delete=models.CASCADE, null=True, blank=True)
    Smartphone_accessory_detail = models.OneToOneField(Smartphone_accessory_detail, on_delete=models.CASCADE, null=True, blank=True)

    class Meta:
        verbose_name_plural = 'products'

    def get_absolute_url(self):
        return reverse('core:product_detail', args={self.slug})
    
    def __str__(self):
        return self.title

I tried using Case, when models to get the results that I want but wasn't able to figure it out so if someone know a good blogpost that explains how to use case, value, when of django db models please link them.

admin.py

from django.contrib import admin
from .models import Category, Product, Brand, Smartphone_detail, Smartphone_accessory_detail

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ['name', 'slug']
    prepopulated_fields = {'slug': ('name',)}

@admin.register(Brand)
class BrandAdmin(admin.ModelAdmin):
    list_display = ['name', 'slug', 'description', 'image']
    prepopulated_fields = {'slug': ('name',)}
    
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = [
        'title', 'slug', 'price',
        'description', 'in_stock', 'image'
    ]
    prepopulated_fields = {'slug': ('title',)}

@admin.register(Smartphone_detail)
class Smartphone_detailAdmin(admin.ModelAdmin):
    list_display = [
        'name', 'brand', 'ram', 'storage',
        'camera', 'processor', 'fingerprint',
        'battery', 'charger', 'charging_speed'
    ]

@admin.register(Smartphone_accessory_detail)
class Smartphone_accessory_detailAdmin(admin.ModelAdmin):
    list_display = [
        'name', 'brand', 'type'
    ]

urls.py

from django.urls import path
from . import views

app_name = 'core'

urlpatterns = [
    path('', views.index, name='index'),
    path('product/<slug:slug>/', views.product_detail, name='product_detail'),
    path('search/<slug:category_slug>/', views.category_list, name='category_list'),
]

detail.html

{% extends '../base.html' %}

{% block title %}{{ product.title }}{% endblock title %}

{% block content %}

<div >
    <div >
        <div >
            <img  alt={{ product.title }} src="{{ product.image.url }}"/>
        </div>
        <div >
            <div >
                <div >
                    <h1 >{{ product.title }}</h1>
                </div>
            </div>
            <div >
                <div >
                    <h3>&#8377;{{ product.price }}</h3>
                </div>
            </div>
            <div >
                <div >
                    <p>{{ product.description }}</p>
                </div>
            </div>
        </div>
    </div>
    <!-- Table for SmartphoneDetail section -->
    <table >
        <tbody>
            <tr>
                <td >name</td>
                <td>{{ product.smartphone_detail.name }}</td>
            </tr>
            <tr>
                <td >brand</td>
                <td>{{ product.smartphone_detail.brand }}</td>
            </tr>
            <tr>
                <td >ram</td>
                <td>{{ product.smartphone_detail.ram }}Gb</td>
            </tr>
            <tr>
                <td >storage</td>
                <td>{{ product.smartphone_detail.storage }}Gb</td>
            </tr>
            <tr>
                <td >camera</td>
                <td>{{ product.smartphone_detail.camera }}</td>
            </tr>
            <tr>
                <td >processor</td>
                <td>{{ product.smartphone_detail.processor }}</td>
            </tr>
            <tr>
                <td >fingerprint</td>
                <td>{{ product.smartphone_detail.fingerprint }}</td>
            </tr>
            <tr>
                <td >battery</td>
                <td>{{ product.smartphone_detail.battery }}</td>
            </tr>
            <tr>
                <td >charger</td>
                <td>{{ product.smartphone_detail.charger }}</td>
            </tr>
            <tr>
                <td >charging speed</td>
                <td>{{ product.smartphone_detail.charging_speed }}</td>
            </tr>

        </tbody>
    </table>
</div>

{% endblock content %}

Here when I try to write a if statement it stops rendering this table in my detail page. so if anyone can guide me how to write a if statement which only renders the details related to that product not unnecessary details.

I want to write the statement if the product is in smartphone category then only show the smartphone detail not the other ones but I don't know how to write this statement because the categories are added from the Django admin panel not from the models.

This question is solved by nigel222 thanks for your answer. I followed his answer and got on the conclution that this code works perfect for me.

updated code:

views.py

def product_detail(request, slug):
    product = get_object_or_404(Product, slug=slug, in_stock=True)
    is_smartphone = product.category.filter(name='smartphone').exists()
    is_fashion = product.category.filter(name='fashion').exists()
    is_accessory = product.category.filter(name='accessories').exists()
    return render(request, 'core/products/detail.html', {
        'product': product, 'is_smartphone': is_smartphone,
        'is_fashion': is_fashion, 'is_accessory': is_accessory
    })

detail.html

{% if is_smartphone %}
<table >
    <tbody>
        <tr>
            <td >name</td>
            <td>{{ product.smartphone_detail.name }}</td>
        </tr>
        <tr>
            <td >brand</td>
            <td>{{ product.smartphone_detail.brand }}</td>
        </tr>
        <tr>
            <td >ram</td>
            <td>{{ product.smartphone_detail.ram }}Gb</td>
        </tr>
        <tr>
            <td >storage</td>
            <td>{{ product.smartphone_detail.storage }}Gb</td>
        </tr>
        <tr>
            <td >camera</td>
            <td>{{ product.smartphone_detail.camera }}</td>
        </tr>
        <tr>
            <td >processor</td>
            <td>{{ product.smartphone_detail.processor }}</td>
        </tr>
        <tr>
            <td >fingerprint</td>
            <td>{{ product.smartphone_detail.fingerprint }}</td>
        </tr>
        <tr>
            <td >battery</td>
            <td>{{ product.smartphone_detail.battery }}</td>
        </tr>
        <tr>
            <td >charger</td>
            <td>{{ product.smartphone_detail.charger }}</td>
        </tr>
        <tr>
            <td >charging speed</td>
            <td>{{ product.smartphone_detail.charging_speed }}</td>
        </tr>

    </tbody>
    {% endif %}

    {% if is_accessory %}
    <table >
        <tbody>
            <tr>
                <td >name</td>
                <td>{{ product.smartphone_accessory_detail.name }}</td>
            </tr>
            <tr>
                <td >brand</td>
                <td>{{ product.smartphone_accessory_detail.brand }}</td>
            </tr>
            <tr>
                <td >product type</td>
                <td>{{ product.smartphone_accessory_detail.type }}</td>
            </tr>

        </tbody>
        {% endif %}

CodePudding user response:

We can't help you with how to determine whether the product is a smartphone. You are the one with the deepest understanding of your database.

However, if the determination is complex, then you should do the work in Python and pass a simple boolean value to your template through the context. Even if it's not very complex, this may make the template far more readable than frequent repeats of, say, {% if something == 'somevalue' and someotherthing != 'someothervalue' %}. (e.g. DRY).

For example

def product_detail(request, slug):

    product = get_object_or_404(Product, slug=slug, in_stock=True)

    # as many lines of code as it takes to determine the True/False
    # value of is_smartphone

    return render(request, 'core/products/detail.html', 
        {'product': product, 'is_smartphone': is_smartphone})

In your templates

{% if is_smartphone %} ... {% endif %}

Sometimes useful

{{ is_smartphone|yesno:'smartphone text,other text' }}
  • Related