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>₹{{ 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' }}