Moni,我是Charlie!
在Day27當中我們完成了recaptcha驗證,而今天我們將實作按讚收藏的部分。
================================◉‿◉=================================
首先是後端的部分,按讚收藏需要另外一個資料表,這個資料表會包含以下欄位:
所以我們先新建一個app叫做favorite:
*$ python manage.py startapp favorite
接著在settings.py當中新增INSTALLED_APPS:
INSTALLED_APPS = [
….
'users',
'login',
'resetPWD',
'favorite'...
]
並在favorite APP當中建立models:
from django.db import models
from users.models import User
from product.models import Product
# Create your models here.
class Favorite(models.Model):
id = models.AutoField(primary_key = True)
user = models.ForeignKey(User,on_delete = models.CASCADE,verbose_name = "用戶")
product = models.ForeignKey(Product,on_delete = models.CASCADE,verbose_name = "商品")
created_time = models.DateTimeField(auto_now = True,verbose_name = "創建時間")
modified_time = models.DateTimeField(auto_now = True,verbose_name = "修改時間")
status = models.IntegerField(verbose_name = "狀態")
class Meta:
db_table = "favorite"
並使用指令遷移:
$ python manage.py makemigrations favorite
$ python manage.py migrate favorite
接著建立urls.py,並且修改keyboardmarket\urls.py,新增favorite app url:
keyboardmarket\urls.py
urlpatterns = [
path('admin/', admin.site.urls),
url('favorite',include('favorite.urls')),
url('reset',include('resetPWD.urls')),
url('usercart',include('usercart.urls')),
url('userorder',include('userorder.urls')),
url('user',include('users.urls')),
url('login',include('login.urls')),
url('product',include('product.urls')),
]
favorite\urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$',views.favorite)
]
favorite APP會處理三種請求:
所以在views.py當中建立基本程式碼:
from tools.login_check import logincheck
from tools.R import R
from favorite.models import Favorite
from users.models import User
from product.models import Product
from tools.db import FavoriteStatus
import json
# Create your views here.
@logincheck("GET","POST")
def favorite(request,productID = None):
if request.method == "GET" and productID:
pass
if request.method == "GET":
pass
if request.method == "POST":
pass
return R.methodNotAllowed("method not allowed")
接著在tools\db.py當中建立FavoriteStatus:
class FavoriteStatus(Enum):
deactivate = 0
activate = 1
然後在Favorite model建立toJson方法:
def toJson(self):
data = {}
data["id"] = self.id
data["username"] = self.user.name
data["product"] = self.product.toJson()
data["created_time"] = self.created_time
data["modified_time"] = self.modified_time
data["status"] = self.status
return data
先修改GET的部分,GET會讀到username的參數,如果有讀到的話就會查詢按讚紀錄,並返回資料:
if request.method == "GET":
req = request.GET
if "username" not in req:
return R.badRequest("username does not exist")
username = req["username"]
user = User.objects.filter(name = username)
if not user:
return R.badRequest("User not found")
user = user[0]
favorites = Favorite.objects.filter(user = user).filter(status = FavoriteStatus.activate.value)
favorites = [i.toJson() for i in favorites]
return R.ok(favorites)
再來是POST的部分,這部分需要判斷的比較多,如果沒有此筆資料的話要新增按讚資料,如果有此筆資料的話如果狀態為1就更改為狀態為0,如果狀態為0則更改狀態為1:
if request.method == "POST":
req = request.body
data = json.loads(req)
if "username" not in data or "pid" not in data:
return R.badRequest("not enough parameters!")
username = data["username"]
user = User.objects.filter(name = username)
if not user:
return R.badRequest("User not found")
user = user[0]
pid = data["pid"]
product = Product.objects.filter(id = pid)
if not product:
return R.badRequest("product does not exist!")
product = product[0]
favorite = Favorite.objects.filter(user = user).filter(product = product)
if not favorite:
favorite = Favorite.objects.create(
user = user,
product = product,
status = FavoriteStatus.activate.value
)
else:
favorite = favorite[0]
if favorite.status == FavoriteStatus.activate.value:
favorite.status = FavoriteStatus.deactivate.value
else:
favorite.status = FavoriteStatus.activate.value
favorite.save()
return R.ok({"status":favorite.status})
再來是個別商品的部分:
if request.method == "GET" and productID:
req = request.GET
if "username" not in req:
return R.badRequest("username does not exist")
username = req["username"]
user = User.objects.filter(name = username)
if not user:
return R.badRequest("User not found")
user = user[0]
product = Product.objects.filter(id = productID)
if not product:
return R.badRequest("Product does not exist")
product = product[0]
favorite = Favorite.objects.filter(user = user).filter(product = product)
data = {
"status":0
}
if favorite:
data["status"] = favorite[0].status
return R.ok(data)
再來是前端的部分,到apis資料夾當中新增favorite.js,並且新增加載商品按讚狀態跟按讚的API:
import { host,port } from '@/apis/constant.js'
import axios from 'axios'
export function getProductFavorite(pid,token,username){
return axios.get(`http://${host()}:${port()}/favorite/${pid}`,{
params:{
"username":username
},
headers:{
"AUTHORIZATION":token
}
})
}
export function addFavorite(pid,token,username){
return axios.post(`http://${host()}:${port()}/favorite`,{
"username":username,
"pid":pid
},{
headers:{
"AUTHORIZATION":token
}
})
}
到productDetail中新增按讚按紐:
<b-button variant="info">
{{ favoriteText }}
</b-button>
並在created方法當中新增獲取商品按讚狀態的程式碼:
var token = window.localStorage.getItem("token")
var username = window.localStorage.getItem("username")
if(token == null || username == null){
this.favoriteText = "登入以按讚"
}else{
getProductFavorite(pid,token,username).then((response) => {
if(response.data.code == STATUS_OK){
var status = response.data.data.status
this.favoriteText = status == 0 ? "按讚" : "已按讚"
}
})
}
接著在按讚按鈕上新增onclick function:
<b-button variant="info" @click="addToFavorite">
{{ favoriteText }}
</b-button>
並且新增addToFavorite方法,打後端的按讚API,並且根據狀態顯示不同按鈕文字:
addToFavorite(){
var pid = this.$route.params.pid
var username = window.localStorage.getItem("username")
var token = window.localStorage.getItem("token")
if(username == null || token == null){
this.$fire({type:"error",text:"請登入!"}).then(() => {
location.href = "/#/login"
})
}else{
addFavorite(pid,token,username).then((response) => {
if(response.data.code == STATUS_OK){
this.favoriteText = response.data.data.status == 0 ? "按讚" : "已按讚"
}
})
}
},
就可以測試看看是否可以按讚了:
接下來是按讚好物的部分,在headers當中新增:
<b-nav-item-dropdown text="會員" right>
<b-dropdown-item href="/#/login" v-show="!isLogin">登入</b-dropdown-item>
<b-dropdown-item href="/#/register" v-show="!isLogin">註冊</b-dropdown-item>
<b-dropdown-item href="/#/self" v-show="isLogin">個人資料</b-dropdown-item>
<b-dropdown-item href="/#/favorite" v-show="isLogin">按讚好物</b-dropdown-item>
<b-dropdown-item href="/#/order" v-show="isLogin">訂單</b-dropdown-item>
<b-dropdown-item v-show="isLogin" @click="logout">登出</b-dropdown-item>
</b-nav-item-dropdown>
另外新增components\favorite.vue,做出模板:
<template>
<html lang="zh-Hant-TW">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/x-con" href="@/assets/favicon.ico">
<div id="app">
<headerComponent></headerComponent>
<div id="favoriteHeader" style="width:100%;height:100px;background-image: linear-gradient(to right,#C9C9C9,#F2FFFF,#00E6E6);padding-top: 40px;">
<h3>按讚好物</h3>
</div>
<b-row>
<b-col cols="2" v-for="item in items" :key="item.id" style="margin: 20px;border:1px solid #5B5B5B;padding: 10px;text-align: center;box-shadow:3px 3px 12px #4F4F4F;border-radius: 30px;">
<a :href="'/#/productDetail/' + item.product.id">
<img :src="'http://localhost:8000' + item.product.img" alt="" style="width: 200px;height: 200px;">
</a>
<h4 class="productTitle">
{{ item.product.name }}
</h4>
<h5 class="productPrice">
{{ item.product.price }}
</h5>
<div>
<b-button variant="danger" @click="cancel(item.product.id)">
取消按讚
</b-button>
</div>
</b-col>
</b-row>
</div>
</html>
</template>
<script>
export default{
name: "favoritePage",
components:{
'headerComponent':() => import('@/components/header.vue')
},
data(){
return {
items:[
{
"id":1,
"username":"admin123",
"product":{
"id":3,
"name":"耳機",
"price":123,
"stored_amount":12,
"img":"/media/productImage/airpod.png"
}
}
]
}
},
methods:{
cancel(data){
console.log(data)
}
}
}
</script>
呈現出來的頁面:
在favorite.js當中新增getAllFavorite方法:
export function getAllFavorite(username,token){
return axios.get(`http://${host()}:${port()}/favorite`,{
"username":username
},{
headers:{
"AUTHORIZATION":token
}
})
}
並新增created方法,使用getAllFavorite方法取得資料:
created(){
var token = window.localStorage.getItem("token")
var username = window.localStorage.getItem("username")
if(token == null || username == null){
this.$fire({type:"error",text:"請登入"}).then(() => {
location.href = "/#/login"
})
}
getAllFavorite(username,token).then((response) => {
if(response.data.code == STATUS_OK){
this.items = response.data.data
}else{
this.$fire({type:"error",text:response.data.data})
}
})
},
接著新增取消方法,這裡使用的是在商品詳情頁面用過的addFavorite API,讓後端自動判定狀態:
cancel(data){
var token = window.localStorage.getItem("token")
var username = window.localStorage.getItem("username")
var pid = data
addFavorite(pid,token,username).then((response) => {
if(response.data.code == STATUS_OK){
this.items.forEach((item,index) => {
if(item.product.id == pid){
this.items.splice(index,1)
}
})
}
})
}
即可測試是否可以按讚跟收回,還有取消後會不會從按讚好物清單中消失。
================================◉‿◉=================================
Day28結束了!在今天我們完成了按讚跟取消按讚還有收藏的機制,而明天我們將加上像是Facebook分享、Line分享的按紐,See ya next day!