[不做怎麼知道系列之Android開發者的30天後端養成故事 Day9] - 真正的連接前後端 #前端資料從後端撈 #串過MVT #Models-to-Templates

哈囉,我們又見面了,今天來看看我們怎麼從資料庫撈資料,然後呈現到 昨天 套好的樣板上吧 !

先來看看今天的結果長什麼樣子吧~

https://youtu.be/wWKHwkMsAPg

其實跟昨天幾乎一樣,因為我沒有換照片 XD,但實際上,畫面上顯示的產品資訊,全都是我透過 Django 從 SQLite 資料庫裡面撈出來(包括產品照片),並且將資料一層一層的傳出來到畫面上。

附上昨天的版本作為比較

https://youtu.be/3IYzpy5vcwA

其實就是把產品名稱換掉、換產品標籤(e.g. New Arrival 換成 新品到貨)以及換價格。

今天的學習重點

在於「如何從資料庫取得資料,並將資料一層一層的傳到畫面上」,其中的一層一層就包含了,在 models.py 定義好產品屬性、設定圖片儲存路徑、建立產品資料到資料庫裡、從 views.py 抓出存放在資料庫的資料 並 以 context 的方式將產品資料傳到 html,最後,在 html 端把 context 裡的產品資料解析,並分別放到該放的地方。除了層層傳遞之外,還有注意 存取圖片資源的路徑,也是今天的重點之一。

所以一個產品應該包含哪些屬性呢 ?

我這邊因為是用賣衣服的樣板,所以就照著這樣來設計吧,衣服的基本屬性大概就會有

  • 產品名稱
  • 產品圖片
  • 產品價格
  • 產品特價後的價格

其餘可以針對你的使用需求,自定義你想要的屬性唷。

先在 models.py 定義產品的屬性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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

別忘了只要有更改 models.py 的內容,就要

$ python manage.py makemigrations

$ python manage.py migrate

如果用上述兩個還有問題的話,那可以試著把你的 db.sqlite3 砍掉,然後重跑上面兩行。

再來設定圖片的儲存路徑

也就是我們之後上傳產品圖片後,會存放在哪個資料夾底下,存取也會從這個資料夾讀取。

settings.py

1
2
3
4
5
6
7
8
9
... # 前面太長,省略

# 昨天設定的 static 路徑
STATIC_URL = '/static/'

# 今天的重點之一,上傳產品圖片後,會存放的地方
# Media root for storing uploads in model
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

urls.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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,裡面就會看到下面的畫面

透過 admin 來新增我們的產品資訊囉

來到新增的頁面,就可以看到剛剛開好的屬性都在這裡了~ 非常方 ban 呢

如果填好資料後,按下右下角的 Save and continue editing,值得一提的是,新增照片的部分,會存在 uploads/ 底下,而且如果圖片上傳有重複的檔名,還會幫你加個亂碼呢。

上傳的圖片實際上是會 被放在 /media/uploads 底下,我特地把「被放在」給標粗體,是因為這是我們設定好路徑,並透過 django 上傳後的圖片,我們不用自己把檔案放到這裡去。

新增完畢就會長這樣

確認圖片能夠真的被存取到

進到 Product 1 的頁面,點進去照片存放的路徑,如果能成功瀏覽到圖片,那這樣就是成功囉,壓呼~

產品都弄好了,那麼就剩呈現囉 !

這邊的概念就是在 views.py 拿到存放在資料庫的 Product 資料,包成 context 再傳給 html,html 再把產品資訊拆開,放到各個地方。

views.py

1
2
3
4
5
6
7
8
9
10
11
# 記得引入我們設計好的 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...

<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

最後結果再貼一次最上面的影片

https://youtu.be/wWKHwkMsAPg

可以在 admin,把產品資訊改一改,看網頁上會不會直接跟著變,來檢驗看看是不是有成功連結到資料庫唷。

單日心得總結

今天光是把購物車、結帳、關於的幾個頁面導入就花了不少時間,還有把各個頁面重複的地方,重構放到 base.html,再加上要設計 Product model 屬性、瞭解幾個 model field 的參數有哪些是必放的,最後再被 media 路徑搞好久 QQ,還好參考了 Setting django’s static and media URLS,革命成功,YA。

今天沒什麼休息從早上十點,直接做做做,做到下午五點多才完成今天的進度,然後吃個飯之後開始寫今天這篇文章,現在加上排版、校稿,已經晚上九點,雖然累,但老實講還蠻爽的,覺得自己有持續在進步的感覺,真的 hen 棒~

我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。


  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2021-2022 Sam Ho
  • Visitors: | Views:

請我喝杯咖啡吧~

支付宝
微信