iT邦幫忙

1

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

Sam 2020-02-12 20:56:454417 瀏覽

https://ithelp.ithome.com.tw/upload/images/20200212/20124548YqGMJE70NK.png

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

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

Yes

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

附上昨天的版本作為比較

Yes

其實就是把產品名稱換掉、換產品標籤(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

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

$ 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,裡面就會看到下面的畫面

https://ithelp.ithome.com.tw/upload/images/20200212/201245484TgebRkaAo.png

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

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

https://ithelp.ithome.com.tw/upload/images/20200212/20124548dwACKkXkCV.png

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

https://ithelp.ithome.com.tw/upload/images/20200212/20124548UUks3PhgX2.png

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

https://ithelp.ithome.com.tw/upload/images/20200212/20124548SSq6jSY0uA.png

新增完畢就會長這樣

https://ithelp.ithome.com.tw/upload/images/20200212/201245482bBvMI76u1.png

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

https://ithelp.ithome.com.tw/upload/images/20200212/20124548eYZl7NyNXf.png

右圖,要改成 下圖,這邊的編輯器不允許我左右並排 QQ

https://ithelp.ithome.com.tw/upload/images/20200212/20124548zHGfY8GXNm.png

進到 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

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

Yes

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

單日心得總結

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

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

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



圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言