哈囉,我們又見面了,今天來看看我們怎麼從資料庫撈資料,然後呈現到 昨天 套好的樣板上吧 !
其實跟昨天幾乎一樣,因為我沒有換照片 XD,但實際上,畫面上顯示的產品資訊,全都是我透過 Django 從 SQLite 資料庫裡面撈出來(包括產品照片),並且將資料一層一層的傳出來到畫面上。
其實就是把產品名稱換掉、換產品標籤(e.g. New Arrival 換成 新品到貨)以及換價格。
在於「如何從資料庫取得資料,並將資料一層一層的傳到畫面上」,其中的一層一層就包含了,在 models.py
定義好產品屬性、設定圖片儲存路徑、建立產品資料到資料庫裡、從 views.py
抓出存放在資料庫的資料 並 以 context 的方式將產品資料傳到 html,最後,在 html 端把 context 裡的產品資料解析,並分別放到該放的地方。除了層層傳遞之外,還有注意 存取圖片資源的路徑,也是今天的重點之一。
我這邊因為是用賣衣服的樣板,所以就照著這樣來設計吧,衣服的基本屬性大概就會有
其餘可以針對你的使用需求,自定義你想要的屬性唷。
models.py
定義產品的屬性from django.db import models
from django.utils import timezone
import os
# 產品圖片的存放路徑是 media/uploads/xxx.jpg,
# 而存放在 DB 的路徑是 uploads/xxx.jpg
# 所以我們在 html 使用時,需要自己補 /media/ 的前綴
# 在 html 的完整使用是 /media/{product.0.img}
def get_image_path(instance, filename):
return os.path.join('uploads', filename)
class Product(models.Model):
# basic info,基本屬性
name = models.CharField(
max_length=100, blank=False
)
price = models.DecimalField(
blank=False, max_digits=100, decimal_places=0
)
img = models.ImageField(
upload_to=get_image_path,
default=get_image_path(
instance=0, filename='product-1.jpg'
)
)
# discount,跟折扣相關的屬性
on_sale = models.BooleanField(
blank=True, null=True
)
tag = models.CharField(
max_length=20, blank=True, null=True
)
percent_off = models.DecimalField(
blank=True, null=True, max_digits=30, decimal_places=1
)
sale_price = models.DecimalField(
blank=True, null=True, max_digits=30, decimal_places=0
)
# for analysis,網頁使用者看不到,但可事後分析的屬性
bought_counter = models.DecimalField(
default=0, max_digits=30, decimal_places=0
)
created_date = models.DateTimeField(
default=timezone.now
)
published_date = models.DateTimeField(
blank=True, null=True
)
def publish(self):
self.published_date = timezone.now
self.save()
def __str__(self):
return self.name
$ python manage.py makemigrations
$ python manage.py migrate
如果用上述兩個還有問題的話,那可以試著把你的 db.sqlite3
砍掉,然後重跑上面兩行。
也就是我們之後上傳產品圖片後,會存放在哪個資料夾底下,存取也會從這個資料夾讀取。
settings.py
... # 前面太長,省略
# 昨天設定的 static 路徑
STATIC_URL = '/static/'
# 今天的重點之一,上傳產品圖片後,會存放的地方
# Media root for storing uploads in model
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
urls.py
from django.contrib import admin
from django.urls import path
from shop.views import shop_view, product_view, \
about_view, cart_view, checkout_view
from django.conf import settings
from django.conf.urls.static import static
# 阿對,我自己先把其他頁面給導入了
# 因為是苦力活,跟昨天所提到的重點一模模一樣樣
urlpatterns = [
path('admin/', admin.site.urls),
path('', shop_view),
path('product/', product_view),
path('about/', about_view),
path('cart/', cart_view),
path('checkout/', checkout_view),
]
# 今日重點,是我們能夠讀取到圖片的關鍵
# 將存取路徑正確地導到圖片存放的路徑
urlpatterns += static(
settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT
)
只要上面兩行有執行成功,那麼開 127.0.0.1:8000/admin
,裡面就會看到下面的畫面
來到新增的頁面,就可以看到剛剛開好的屬性都在這裡了~ 非常方 ban 呢
如果填好資料後,按下右下角的 Save and continue editing
,值得一提的是,新增照片的部分,會存在 uploads/
底下,而且如果圖片上傳有重複的檔名,還會幫你加個亂碼呢。
上傳的圖片實際上是會 被放在 /media/uploads
底下,我特地把「被放在」給標粗體,是因為這是我們設定好路徑,並透過 django 上傳後的圖片,我們不用自己把檔案放到這裡去。
右圖,要改成 下圖,這邊的編輯器不允許我左右並排 QQ
進到 Product 1 的頁面,點進去照片存放的路徑,如果能成功瀏覽到圖片,那這樣就是成功囉,壓呼~
這邊的概念就是在 views.py
拿到存放在資料庫的 Product 資料,包成 context 再傳給 html,html 再把產品資訊拆開,放到各個地方。
views.py
# 記得引入我們設計好的 model 唷
from .models import Product
def shop_view(request):
context = {
... ,
# 將 QuerySet 轉成 list
# 以 context 的方式傳給 templates
'products': list(Product.objects.all())
}
return render(
request,
'shop/shop.html',
context
)
shop.html
...
<div class="product">
<a href="/product" class="img-prod"><img class="img-fluid" src="/media/{{ products.0.img }}" alt="{{ products.0.name }}">
<span class="status">{{ products.0.tag }}</span>
</a>
<div class="text py-3 px-3">
<h3><a href="/product">{{ products.0.name }}</a></h3>
<div class="d-flex">
<div class="pricing">
<p class="price"><span class="mr-2 price-dc">${{ products.0.price }}</span><span class="price-sale">${{ products.0.sale_price }}</span></p>
</div>
</div>
</div>
</div>
...
值得注意的一點是 <a>
tag 內放的 img 的 src 路徑是 /media/{{ products.0.img }}
,前面要記得自己加個 /media/
前綴,我還沒找到方法可以略過它 QQ,然後其他的屬性,舉例產品名稱,可以直接對 Product 物件存取它的屬性方法,非常方便而且好理解阿~,html 實在是太長,原始碼可以參考我的 Github。
可以在 admin,把產品資訊改一改,看網頁上會不會直接跟著變,來檢驗看看是不是有成功連結到資料庫唷。
今天光是把購物車、結帳、關於的幾個頁面導入就花了不少時間,還有把各個頁面重複的地方,重構放到 base.html
,再加上要設計 Product model 屬性、瞭解幾個 model field 的參數有哪些是必放的,最後再被 media 路徑搞好久 QQ,還好參考了 Setting django's static and media URLS,革命成功,YA。
今天沒什麼休息從早上十點,直接做做做,做到下午五點多才完成今天的進度,然後吃個飯之後開始寫今天這篇文章,現在加上排版、校稿,已經晚上九點,雖然累,但老實講還蠻爽的,覺得自己有持續在進步的感覺,真的 hen 棒~
我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。