iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0

Day 16 佈置房間, 將資料傳入 Template

大廳裝潢完還有房間呢,接續昨天的首頁套版,我們將取用之前建立的首頁資料與套用商品列表頁面、商品詳細頁面,現在馬上就開始!

首頁資料套用

套用了新頁面後可不能忘了取用我們之前建立的的資料,新首頁我們不只顯示商品列表還多了商品分類區塊,這代表我們在首頁對應的視圖 HomeView 需要取得商品分類的資料

在 context 新增了 left_product_categories 來儲存商品分類的左側的兩筆資料,right_product_category 來儲存商品分類的右側的一筆資料,以下為更新後的 HomeView :

# products/views.py
from django.views.generic import TemplateView, ListView, DetailView
from products.models import Product, ProductCategory

class HomeView(TemplateView):
    template_name = "products/home.html"

    def get(self, request, *args, **kwargs):
        products = Product.objects.all()
        left_product_categories = ProductCategory.objects.all()[0:2]
        right_product_categories = ProductCategory.objects.all()[2:3]
        right_product_category = right_product_categories.first() if right_product_categories else None
        context = self.get_context_data(**kwargs)
        context['items'] = products
        context['left_product_categories'] = left_product_categories
        context['right_product_category'] = right_product_category
        return self.render_to_response(context)

在 home.html 使用 left_product_categories 與 right_product_category 來呈現商品分類資料,

使用 DTL 的 . 語法對查找 ImageField 物件的 url 時,需要先判斷 image 是否存在,否則沒有圖片時直接取用 url 會出現錯誤。

<!-- products/templates/products/home.html -->
{% extends "base.html" %}
{% load static %}

{% block content %}
<section class="product-category section">
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="title text-center">
                    <h2>以商品分類尋找屬於您的商品</h2>
                </div>
            </div>
            <div class="col-md-6">
                {% for left_product_category in left_product_categories %}
                    <div class="category-box">
                        <a href="#!">
                            {% if left_product_category.image %}
                                <img src="{{ left_product_category.image.url }}" alt="" />
                            {% endif %}
                            <div class="content">
                                <h3 style="color: white;">{{ left_product_category.name }}</h3>
                                <p style="color: white;">{{ left_product_category.description }}</p>
                            </div>
                        </a>	
                    </div>
                {% endfor %}
            </div>
            <div class="col-md-6">
                <div class="category-box category-box-2">
                    <a href="#!">
                        {% if right_product_category.image %}
                            <img src="{{ right_product_category.image.url }}" alt="" />
                        {% endif %}
                        <div class="content">
                            <h3 style="color: white;">{{ right_product_category.name }}</h3>
                            <p style="color: white;">{{ right_product_category.description }}</p>
                        </div>
                    </a>
                </div>
            </div>
        </div>
    </div>
</section>

<section class="products section bg-gray">
<!-- ...  -->
</section>
{% endblock content %}

商品分類區塊展示:

https://ithelp.ithome.com.tw/upload/images/20220928/201516568Nn0WFriPc.png

下方的商品列表與原先一樣使用 items 取得所有商品資料,商品圖片因為關聯到 ProductImage 模型,使用 related_name 取得所有關聯物件,再使用 .0 取用第一張圖片,另外要注意 html 使用了 modal 互動視窗,因此要透過 item.id 進行對應

<!-- products/templates/products/home.html -->
{% extends "base.html" %}
{% load static %}

{% block content %}
<section class="product-category section">
<!-- ...  -->
</section>

<section class="products section bg-gray">
    <div class="container">
        <div class="row">
            <div class="title text-center">
                <h2>所有商品</h2>
            </div>
        </div>
        <div class="row">
            {% for item in items %}
                <div class="col-md-4">
                    <div class="product-item">
                        <div class="product-thumb">
                            {% if item.product_image_set.all.0.image %}
                                <img class="img-responsive" src="{{ item.product_image_set.all.0.image.url }}" alt="product-img" />
                            {% endif %}
                            <div class="preview-meta">
                                <ul>
                                    <li>
                                        <span  data-toggle="modal" data-target="#product-modal-{{ item.id }}">
                                            <i class="tf-ion-ios-search-strong"></i>
                                        </span>
                                    </li>
                                    <li>
                                        <a href="#" ><i class="tf-ion-ios-heart"></i></a>
                                    </li>
                                    <li>
                                        <a href="#!"><i class="tf-ion-android-cart"></i></a>
                                    </li>
                                </ul>
                            </div>
                        </div>
                        <div class="product-content">
                            <h4><a href="product-single.html">{{ item.name }}</a></h4>
                            <p class="price">${{ item.price }}</p>
                        </div>
                    </div>
                </div>
                <!-- Modal -->
                <div class="modal product-modal fade" id="product-modal-{{ item.id }}">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <i class="tf-ion-close"></i>
                    </button>
                    <div class="modal-dialog " role="document">
                        <div class="modal-content">
                            <div class="modal-body">
                                <div class="row">
                                    <div class="col-md-8 col-sm-6 col-xs-12">
                                        <div class="modal-image">
                                            {% if item.product_image_set.all.0.image %}
                                                <img class="img-responsive" src="{{ item.product_image_set.all.0.image.url }}" alt="product-img" />
                                            {% endif %}
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6 col-xs-12">
                                        <div class="product-short-details">
                                            <h2 class="product-title">{{ item.name }}</h2>
                                            <p class="product-price">${{ item.price }}</p>
                                            <p class="product-short-description">
                                                {{ item.description }}
                                            </p>
                                            <a href="cart.html" class="btn btn-main">加入購物車</a>
                                            <a href="{% url 'products:detail' item.id %}" class="btn btn-transparent">檢視商品詳細資料</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div><!-- /.modal -->
            {% endfor %}
        </div>
    </div>
</section>
{% endblock content %}

商品列表區塊展示:

https://ithelp.ithome.com.tw/upload/images/20220928/201516566qukCo3CmB.png

點選檢視 modal 互動視窗:

https://ithelp.ithome.com.tw/upload/images/20220928/20151656yQ12Nc1bPN.png

商品列表頁面

將 aviato/shop.html 更名為 list.html 並取代 products 應用程式目錄中的 template/products/list.html。

商品列表頁面與首頁的商品列表區塊大同小異,在上方新增了 page-header 來呈現 breadcrumb 麵包屑,而商品列表區塊則是移除了 title 。


<!-- products/templates/products/list.html -->
{% extends "base.html" %}
{% load static %}

{% block content %}
<section class="page-header">
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="content">
                    <h1 class="page-name">全部商品</h1>
                    <ol class="breadcrumb">
                        <li><a href="{% url 'products:home' %}">首頁</a></li>
                        <li class="active"><a href="{% url 'products:list' %}">商品列表</a></li>
                    </ol>
                </div>
            </div>
        </div>
    </div>
</section>

<section class="products section">
    <div class="container">
        <div class="row">
            {% for item in items %}
                <div class="col-md-4">
                    <div class="product-item">
                        <div class="product-thumb">
                            {% if item.product_image_set.all.0.image %}
                                <img class="img-responsive" src="{{ item.product_image_set.all.0.image.url }}" alt="product-img" />
                            {% endif %}
                            <div class="preview-meta">
                                <ul>
                                    <li>
                                        <span  data-toggle="modal" data-target="#product-modal-{{ item.id }}">
                                            <i class="tf-ion-ios-search-strong"></i>
                                        </span>
                                    </li>
                                    <li>
                                        <a href="#" ><i class="tf-ion-ios-heart"></i></a>
                                    </li>
                                    <li>
                                        <a href="#!"><i class="tf-ion-android-cart"></i></a>
                                    </li>
                                </ul>
                            </div>
                        </div>
                        <div class="product-content">
                            <h4><a href="product-single.html">{{ item.name }}</a></h4>
                            <p class="price">${{ item.price }}</p>
                        </div>
                    </div>
                </div>
                <!-- Modal -->
                <div class="modal product-modal fade" id="product-modal-{{ item.id }}">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <i class="tf-ion-close"></i>
                    </button>
                    <div class="modal-dialog " role="document">
                        <div class="modal-content">
                            <div class="modal-body">
                                <div class="row">
                                    <div class="col-md-8 col-sm-6 col-xs-12">
                                        <div class="modal-image">
                                            {% if item.product_image_set.all.0.image %}
                                                <img class="img-responsive" src="{{ item.product_image_set.all.0.image.url }}" alt="product-img" />
                                            {% endif %}
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6 col-xs-12">
                                        <div class="product-short-details">
                                            <h2 class="product-title">{{ item.name }}</h2>
                                            <p class="product-price">${{ item.price }}</p>
                                            <p class="product-short-description">
                                                {{ item.description }}
                                            </p>
                                            <a href="cart.html" class="btn btn-main">加入購物車</a>
                                            <a href="{% url 'products:detail' item.id %}" class="btn btn-transparent">檢視商品詳細資料</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div><!-- /.modal -->
            {% endfor %}
        </div>
    </div>
</section>

{% endblock content %}

商品列表頁面展示:

https://ithelp.ithome.com.tw/upload/images/20220928/20151656Wc9e9hV12A.png

商品詳細頁面

將 aviato/product-single.html 更名為 detail.html 並取代 products 應用程式目錄中的 template/products/detail.html。

這裡會使用到 DTL for 語法的 forloop.counter 進行迴圈計數,當第一次迴圈時將 class 加上 active 屬性,而 add 則是 DTL 的加法運算,用於計算縮圖的對應的位置

<!-- products/templates/products/detail.html -->
{% extends "base.html" %}
{% load static %}

{% block content %}

<section class="single-product">
    <div class="container">
        <div class="row">
            <div class="col-md-6">
                <ol class="breadcrumb">
                    <li><a href="{% url 'products:home' %}">首頁</a></li>
                    <li><a href="{% url 'products:list' %}">商品列表</a></li>
                    <li class="active">商品詳細資料</li>
                </ol>
            </div>
        </div>
        <div class="row mt-20">
            <div class="col-md-5">
                <div class="single-product-slider">
                    <div id='carousel-custom' class='carousel slide' data-ride='carousel'>
                        <div class='carousel-outer'>
                            <!-- me art lab slider -->
                            <div class='carousel-inner '>
                                {% for product_image in item.product_image_set.all %}
                                    {% if forloop.counter == 1 %}
                                        <div class='item active'>
                                    {% else %}
                                        <div class='item'>
                                    {% endif  %}
                                        {% if product_image.image %}
                                            <img src='{{ product_image.image.url }}' alt='' data-zoom-image="{{ product_image.image.url }}" />
                                        {% endif  %}
                                    </div>
                                {% endfor  %}
                            </div>
                            <!-- sag sol -->
                            <a class='left carousel-control' href='#carousel-custom' data-slide='prev'>
                                <i class="tf-ion-ios-arrow-left"></i>
                            </a>
                            <a class='right carousel-control' href='#carousel-custom' data-slide='next'>
                                <i class="tf-ion-ios-arrow-right"></i>
                            </a>
                        </div>
                        
                        <!-- thumb -->
                        <ol class='carousel-indicators mCustomScrollbar meartlab'>
                            {% for product_image in item.product_image_set.all %}
                                {% if forloop.counter == 1 %}
                                    <li data-target='#carousel-custom' data-slide-to='0' class='active'>
                                {% else %}
                                    <li data-target='#carousel-custom' data-slide-to='{{ forloop.counter|add:-1 }}'>
                                {% endif  %}
                                {% if product_image.image %}
                                    <img src='{{ product_image.image.url }}' alt='' />
                                {% endif  %}
                                </li>
                            {% endfor %}
                        </ol>
                    </div>
                </div>
            </div>
            <div class="col-md-7">
                <div class="single-product-details">
                    <h2>{{ item.name }}</h2>
                    <p class="product-price">${{ item.price }}</p>
                    
                    <p class="product-description mt-20">
                        {{ item.description }}
                    </p>
                    <div class="product-quantity">
                        <span>數量:</span>
                        <div class="product-quantity-slider">
                            <input id="product-quantity" type="text" value="0" name="product-quantity">
                        </div>
                    </div>
                    <div class="product-category">
                        <span>商品分類:</span>
                        <ul>
                            <li><a href="product-single.html">{{ item.category.name }}</a></li>
                        </ul>
                    </div>
                    <a href="cart.html" class="btn btn-main mt-20">加入購物車</a>
                </div>
            </div>
        </div>
    </div>
</section>

{% endblock content %}

商品詳細頁面展示:

https://ithelp.ithome.com.tw/upload/images/20220928/20151656q3FaYb82rh.png

一次完整的套版流程完成了,是不是開始有電商網站的感覺了呢?

在多租戶的架構下,每個租戶不會只有商品資料不同,網站的 logo 、title 等商家資訊甚至是模板都可能要做出不同的調整,下一回『個人化,Django 多租戶網站設定』走出自己的路!


上一篇
Day 15 裝潢大廳,套用 Template 版面
下一篇
Day 17 個人化,Django 多租戶網站設定
系列文
全能住宅改造王,Django 多租戶架構的應用 —— 實作一個電商網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言