一、BookShop - 基於Django框架的前后端web項目開發實戰


BookShop

目錄:

一、項目介紹

二、項目基本結構和文件層級

三、各模塊主要功能實現邏輯和數據字典

四、其他功能、插件


一、項目介紹

項目:BookShop圖書商城

技術:Python3.7,Django3.2,mysql5.7

概述:

​ 完整的在線商城流程

功能:

​ 前台:首頁,注冊,登陸,類別列表,商品詳情,購物車,訂單
image

​ 后台:首頁,登陸,用戶管理,類別管理,商品管理
image

數據字典:

​ 用戶模型、類別模型、圖書商品模型、封面圖模型、購物車模型、訂單模型、訂單詳情模型

​ 根據項目的功能和要求,設計對應的數據庫、表、字段


二、項目基本結構和文件層級

1.創建project:bookshop

2.創建APP,包括前台APP:myhome,后台APP:myadmin

3.創建 static、templates 文件夾,並為前、后台分區

4.配置 settings.py 文件,APP、MIDDLEWARE、TEMPLATES、DATA、LANGUAGE、TIME、STATIC

5.創建數據庫:bookshop

6.創建前、后台首頁並配置視圖和路由


文件層級

總覽:

image

后台APP:

image

前台APP:

image

后台模板文件:

image

前台模板文件:

image


三、各模塊主要功能實現邏輯和數據字典

后端功能部分 - Python

1.前后台通用功能

登陸、登陸檢測、退出登陸

​ 功能說明:前后台的登陸、退出登陸,以及使用需要登陸才可以進行的操作時,檢測登陸狀態

1.請求方式為GET時,跳轉到登陸頁面,通過form表單將用戶輸入的數據提交到視圖進行驗證

2.請求方式為POST時,接收表單數據,按順序先檢測驗證碼,再根據用戶名獲取用戶對象,最后使用 check_password 驗證密碼是否正確,任一環節未通過則提示並跳轉回登陸頁面

3.密碼正確后進行會話控制,創建 request.session['Admin/VipUser'] 記錄用戶ID、用戶名、頭像等數據

4.登陸檢測:在需要檢測登陸狀態的視圖中(后台中間件、前台添加商品到購物車),通過判斷 request.session['Admin/VipUser'] 中元素的值是否為空來獲取登陸狀態

5.退出登陸: 把存放登陸信息的 request.session['Admin/VipUser'] 內容設為空即可

注:前台登陸或退出登陸時,如果在商品詳情頁,操作后需跳轉回原頁面。所以在跳轉到登陸頁面時還需通過URL傳遞當前路徑 nextpath = {{ request.path }} ,並在提交登錄form表單時把 {{ request.GET.nextpath }} 一起提交到后台
image


登陸驗證碼

​ 功能說明:登陸時顯示,需要正確輸入才可以登陸

1.在視圖中導入 Image、ImageDraw、ImageFont、random、io 模塊

2.定義畫面的背景色、長、寬,背景色需要使用 random 隨機生成

3.創建畫面對象和畫筆對象,調用畫筆的 point() 函數繪制噪點,噪點位置需要使用 random 隨機生成

4.創建驗證碼備選值(全部字母和數字),使用 random 取4個值進行拼接,作為驗證碼,並存入 session 用於驗證

5.構造字體對象、顏色,繪制4個字符,然后調用內存文件處理,把圖片存在內存中,每次調用函數時返回圖片


分頁

​ 功能說明:在后台管理頁或商品展示頁可以將展示的內容分頁

1.導入 Paginator 模塊,實例化分頁對象 ,根據當前頁碼數獲取該頁的數據后分配到模板

2.自定義處理分頁的模板標簽,需要顯示的頁碼為:被選中頁碼 p ,被選中頁碼之前的5頁和之后的4頁,共10個頁碼,定義 start=p-5 end=p-4 記錄頁碼范圍(需要控制 startend 不能超出邊界值)

3.在頁碼范圍內循環並利用字符串拼接 pagehtml += f'<li><a href="?page={i}">{i}</a></li>' ,完成10個頁碼按鈕的顯示,並在首尾拼接:首頁、上一頁、下一頁、尾頁,在首頁時無法點擊上一頁,在尾頁時無法點擊下一頁。將拼接的最終結果反轉義,然后 return

4.在需要分頁的模板中使用 {% load pagetag %} 導入自定義的模板標簽,然后調用上面拼接頁碼的方法實現輸出


搜索

​ 功能說明:在后台管理頁或商品展示頁可以按條件搜索數據

1.接收搜索條件,在視圖中獲取搜索范圍 select 和搜索框 input 中的值,若非空則繼續判斷搜索條件 select

2.根據搜索條件,使用django.db.models 中的 Q 對所有數據進行過濾: data=data.filter(Q(key1__contains=keywords)|Q(key2__contains=keywords)......)

3.將過濾后的數據分配到模板中使用


用戶、類別、商品列表的增刪改

​ 功能說明:在后台管理頁面中展示各自模塊的數據,並提供增、刪、改的功能

1.在加載列表主頁面的視圖中,需要先獲取要展示的數據,默認獲取全部數據,若有搜索、分頁條件則按條件過濾數據,然后把篩選后的最終數據分配到模板進行調用

2.增:在列表頁點擊添加,調用URL中的視圖跳轉到添加頁;提交添加表單后,用戶模塊需要對密碼加密並檢測是否輸入了頭像,類別模塊需要判斷類別的層級並設置對應的 path 值,商品列表需要檢測是否有封面,最后調用模型存儲數據

3.刪:點擊刪除按鈕,前台將獲取該條數據的id並發送ajax請求到后台,后台接收id后獲取對應的對象,用戶模塊需要刪除頭像文件,類別模塊需要判斷該類別下是否有子類別,商品模塊需要刪除封面圖,最后刪除該對象

4.改:在用戶和商品的編輯方法對應的路由中,添加接收id的參數,點擊編輯時獲取該條數據的id並傳到后台,后台獲取該對象並將數據和編輯頁面一起返回;提交表單后后台接收數據,調用模型存儲數據后跳轉到列表頁


2.后台模塊

​ 視圖目錄:bookshop\myadmin\views,模板目錄:bookshop\templates\myadmin

(1).用戶管理模塊:

​ 視圖:UsersViews.py,模板目錄:users

​ 功能:用戶列表,用戶編輯、添加,刪除,頭像上傳

用戶模型

列名 字段 類型 備注
ID id auto primary key
用戶名 username varchar(20)
密碼 password varchar(80)
手機號 phone char(11) unique
頭像 face_url varchar 存儲頭像的路徑
性別 sex tinyint
年齡 age tinyint
注冊時間 addtime datetime
最后登錄時間 savetime datetime
狀態 status int 0:默認,1:禁用

image

上傳頭像或封面

​ 功能說明:在添加用戶、編輯用戶、添加商品封面時調用,完成文件上傳

1.后台接收添加、編輯表單后,根據表單內 face 的值判斷是否輸入了圖片,如果沒有輸入則使用默認圖片

2.如果輸入了圖片,需要調用上傳圖片文件的方法,並更新用戶對象中存儲頭像路徑的字段 face_url

3.上傳圖片的方法:需要先獲取請求中的文件,根據文件名取出文件類型,判斷是否為圖片,再用時間戳、隨機數與文件類型生成新的文件名,然后讀取上傳的文件內容,寫入新文件,最后將新文件路徑 return


(2).類別管理模塊:

​ 視圖:ClassifyViews.py,模板目錄:classify

​ 功能:類別列表,類別添加、刪除、編輯

商品類別模型

列名 字段 類型 備注
ID id auto primary key
類別名稱 name str
父級ID pid int
路徑 path str 頂級分類為0

image

獲取完成排序且有層次關系的類別

​ 功能說明:在類別管理列表,或添加商品時選擇類別的下拉菜單中,把類別排序並按層級顯示

1.使用 extra() 添加新的字段 paths ,值為 pathid 值拼接的結果,這樣就把同一父級類別下的子類別歸到了一起

2.使用 order_by 對新字段 paths 排序,即子類別排在父級類別后面

3.類別的層級越低,拼接的次數越多, path 中的 ',' 也就越多,因此可以根據逗號的數量為類別標識出層級,獲取逗號數量: num = i.path.count(',') - 1 ,添加層級標識: i.nbsp = '|---- ' * num


(3).商品管理模塊:

​ 視圖:BooksViews.py,模板目錄:books

​ 功能:商品列表,商品添加、刪除、編輯

圖書商品模型

列名 字段 類型 備注
ID id auto primary key
所屬類別 classifyid ForeignKey 一對多
書名 title varchar
副標題 subhead varchar
作者 author varchar
出版社 publisher varchar
出版時間 pub_date date
定價 price float
庫存數量 num int
國際標准書號ISBN ISBN varchar
內容簡介 context text

圖書封面圖模型

列名 字段 類型 備注
ID id auto primary key
所屬圖書 bookid ForeignKey 一對多
封面圖url img_url varchar 圖片路徑

image

商品添加以及一對多模型的應用

​ 功能說明:在商品管理列表添加新的商品

1.請求方式為GET則加載添加商品的模板,為POST則接收添加表單的數據

2.檢測是否有封面圖上傳,沒有則提示並跳轉回商品添加頁面

3.類別模型與圖書模型是一對多的關系,外鍵為 classifyid ,但form表單中選擇的圖書類別 value 值為類別的 id ,所以需要實例化類別對象,並將接收的表單數據中,字段 classifyid 值改為類別對象,然后再更新數據到數據庫

4.圖書模型與封面圖模型是一對多的關系,外鍵 bookid 為圖書對象,img_url 為上傳圖片的方法返回的圖片路徑


3.前台模塊

​ 視圖目錄:bookshop\myhome\views,模板目錄:bookshop\templates\myhome

(1).前台首頁模塊:

​ 視圖:首頁:indexViews.py,注冊:loginViews.py

​ 模板:首頁:index.html、注冊:register.html、分類展示頁:category.html、商品詳情頁:bookdetails.html

​ 功能:商品展示、導航分類展示、商品詳情、注冊、登陸
image

注冊和注冊驗證

​ 功能說明:用戶注冊時,需要驗證手機號是否已經存在

1.請求方式為GET時,跳轉到注冊頁面,用戶輸入手機號

2.前台將手機號由ajax請求發送到后台檢測是否注冊,后台根據手機號查找用戶對象,並將結果返回給前台

3.請求方式為POST時,后台接收表單數據,對密碼進行加密,然后調用模型存儲用戶數據,並跳轉到登陸頁面

導航分類

​ 功能說明:在導航欄或側面分類列表中,按層級展示所有頂級類別、子類別以及子類別下的商品

1.獲取所有頂級分類對象列表,使用 for 循環遍歷列表

2.獲取各個頂級分類下的一級子類,並為每個頂級分類對象添加屬性 sub 記錄這些一級子類對象

3.調用時使用循環嵌套輸出,外層循環遍歷頂級分類列表,內層循環遍歷頂級分類的 sub 屬性即子類列表

頂級分類和一級分類跳轉列表

​ 功能說明:在前台所有頁面都可以通過導航欄點擊一個商品類別,跳轉到展示該類別下所有商品的頁面

1.點擊導航中的頂級分類或一級分類后,該分類id會通過URL提交到視圖,根據id獲取分類對象,判斷是否為頂級分類

2.如果是頂級分類,需要獲取其所有子類,再遍歷子類列表獲取各子類下的所有圖書對象

3.如果不是頂級分類,需要先獲取其所屬頂級分類,再獲取頂級分類下的其他子類,以及各子類下的圖書對象

image


(2).購物車模塊:

​ 視圖:cartViews.py,模板:cart.html

​ 功能:添加商品、更新商品數量、刪除商品、檢測登陸

購物車模型

列名 字段 類型 備注
ID id auto primary key
用戶ID uid ForeignKey 一對多
商品ID bid ForeignKey 一對多
數量 num int
是否選中 status int 0:未選,1:選中

image

添加商品到購物車

​ 功能說明:在商品詳情頁可以將商品加入購物車

1.接收ajax提交的POST表單,然后根據 request.session['vipUser'] 檢測登陸狀態,若沒有登陸則提示

2.根據表單中的商品id獲取商品對象,根據 session 獲取用戶對象

3.判斷加入購物車的商品是否已經存在,根據用戶對象獲取購物車對象,然后用商品id進行篩選,再對篩選結果計數

4.如果已經有該商品的購物車對象,取出這個對象直接更新 num ,如果沒有則創建購物車對象更新數據

編輯數量和刪除商品

​ 功能說明:在購物車頁面編輯商品數量或刪除商品

1.接收ajax提交的GET請求,獲取要刪除或編輯的購物車對象id,以及編輯后的數量

2.獲取購物車對象,執行刪除,或更新 num 並保存


(3).訂單模塊:

​ 視圖:orderViews.py,模板位置:order.html

​ 功能:訂單確認、創建訂單

訂單模型

列名 字段 類型 備注
ID id auto primary key
用戶ID uid ForeignKey 一對多
收件人 name varchar
手機號 phone varchar
城市 city varchar
詳細地址 address varchar
總價 totalprice float
備注 remark char null=True
狀態 status int 0:未支付,1:已支付
創建時間 ordertime datetime
支付時間 paytime datetime null=True

訂單詳情模型

列名 字段 類型 備注
ID id auto primary key
訂單ID orderid ForeignKey 一對多
商品ID bid ForeignKey 一對多
商品數量 num int
商品價格 price float

image

創建訂單

​ 功能說明:接收訂單數據,將數據存入數據庫,並將訂單中的商品從購物車中刪除

1.提交訂單后,接收POST請求中form表單的數據,以及URL攜帶的商品id列表,並根據 session 獲取用戶對象

2.根據商品id列表過濾出訂單中的購物車對象列表,遍歷該列表,計算每個購物車對象的小計價格並累加得到總價

3.將用戶對象、計算得到的總價、表單中用戶輸入的信息構建成訂單數據,創建訂單對象更新數據

4.再次遍歷購物車對象列表,每一次循環更新一個與訂單對象關聯的訂單詳情對象,並刪除該購物車對象


前端功能部分 - js

注冊表單驗證

​ 功能說明:注冊時,檢測輸入的手機號和密碼格式是否正確,密碼和確認密碼是否相同

1.請求方式為GET時,跳轉到注冊頁面。為手機號、密碼、確認密碼三個 input 框綁定喪失焦點事件,並定義三個變量,記錄三個輸入框的狀態,只有三個變量同時為 true ,注冊表單才能提交

2.驗證輸入的手機號格式是否正確(第一位為1,后面十位為數字),如果不正確則觸發喪失焦點事件輸入框變為紅色,並為手機號對應的變量賦值 false ;如果手機號格式正確,則發送 ajax 請求到后台驗證手機號是否已經注冊,若沒有注冊,則輸入框變為綠色,並為對應的變量賦值 true

3.驗證輸入的密碼和確認密碼格式是否正確(6-18位,字母、數字、下划線),格式正確再驗證兩個值是否相同,若相同,則輸入框變為綠色,並為對應的變量賦值 true

4.為表單綁定表單提交事件,觸發所有 input 框的喪失焦點事件,並驗證變量,三個變量都為 true 則提交表單

5.后台接收表單數據,調用 make_password 對密碼加密,創建用戶對象並保存數據,然后提示用戶注冊結果並跳轉到登陸


ajax刪除

​ 功能說明:在后台管理頁、購物車頁中,不跳轉頁面刪除數據

1.為刪除按鈕綁定單擊事件

2.獲取當前點擊項的id,並發送ajax請求到后台進行刪除

3.判斷響應的結果,如果后台數據刪除成功,則頁面中刪除該行數據


ajax編輯

​ 功能說明:在后台類別管理頁,不跳轉頁面,雙擊類別名進行編輯

1.為需要編輯的項綁定雙擊事件並定義執行編輯的函數

2.獲取雙擊項中的內容 name 和該條數據的id,創建 input 框顯示 name

3.為 input 框綁定喪失焦點事件,觸發后,獲取編輯后的 name

4.判斷 name 值是否發生改變,沒有改變則還原,改變則發送ajax請求到后台更新 name

5.判斷響應的結果,顯示更新后的 name


圖片預覽

​ 功能說明:在上傳頭像或封面圖時,預覽圖片

1.為上傳控件綁定 change 事件,值改變時觸發

2.根據字段的長度判斷是否輸入了圖片,如果沒有輸入則繼續使用默認頭像

3.輸入了頭像,獲取圖片對象,用 FileReader() 實例化文件讀取對象,讀取上傳的文件數據為 readAsDataURL(file)

4.為文件讀取對象綁定 onload 事件,對象加載時觸發,顯示讀取到的文件 FileReader.result


加入購物車時傳遞商品數據

​ 功能說明:在商品詳情頁點擊加入購物車時,要先登錄,然后傳遞商品數據到后台,同時傳遞路徑用於登陸后跳轉

1.給加入購物車按鈕綁定單擊事件

2.點擊時,根據 request.session.vipUser.id 判斷登陸狀態,沒有登陸則提示,獲取路徑值並跳轉到登陸頁面

3.若已登錄,獲取商品id和數量框中的值,發送ajax請求到后台,把數據添加到購物車


購物車內根據商品數量顯示價格

​ 功能說明:在購物車內,商品的小計價格隨數量改變而改變

1.為購物車內商品數量框綁定喪失焦點事件

2.觸發時,獲取數量框內的值 n 、該商品的id、商品單價

3.發送ajax請求將編輯后的數量 n 和商品id傳到后台更新商品數據

4.根據響應判斷是否更新成功,成功則計算當前價格,並修改小計標簽的文本內容為計算后的結果


購物車內全選商品

​ 功能說明:在購物車內點擊全選時選中所有商品

1.為全選框綁定單擊事件

2.當點擊全選時,使用 prop('checked',this.checked) 為所有選項框設置與全選框相同的狀態

3.調用計算商品總價的方法顯示總價


計算商品總價

​ 功能說明:根據選中的商品及數量,計算商品總價

1.定義變量記錄選中的商品和價格,起始總價值為0,選中商品列表為空列表

2.循環所有 checkboxcheckedtrue 表示選中,獲取該商品的小計價格累加進總價,獲取商品id放入列表

3.修改總價標簽的文本內容為計算后的結果,返回被選中商品id列表


四、其他功能、插件

CSRF驗證

取消保護

​ 如果某些視圖不需要保護,可以使用裝飾器 csrf_exempt,模板中也不需要寫標簽

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def func(request):
    data = request.POST['name']
    return render(request,'myadmin/index.html',{'data':data})

Ajax CSRF 驗證

​ POST 請求需要正確驗證才能返回結果

​ 使用 Ajax 調用的時候,需要在使用 jQuery 的 ajax 或 post 之前加入以下 js 代碼(要寫在模板文件中)

$.ajaxSetup({
           data:{csrfmiddlewaretoken:'{{ csrf_token }}'},
        });

會話控制

​ 在請求中,http是無狀態請求協議。http無法記錄用戶的請求狀態,如第幾次請求、在什么情況下請求、請求前后訪問過哪里,但在web項目中有時是需要記錄一些狀態的,如是否登錄、查看過哪些頁面、獲取用戶偏好等

可以記錄信息的技術:

  • cookie

    • cookie是在瀏覽器中記錄數據,瀏覽器在訪問同一服務器時會主動攜帶該數據
    • 如果cookie丟失,或者換了瀏覽器訪問,那么cookie就不再存在
    • 敏感數據存在瀏覽器中有安全隱患
  • session

    • session是在服務器中記錄數據(文件、數據庫),每個數據生成一個唯一的ID,叫做sessionID
    • sessionID作為cookie存儲在用戶的瀏覽器中,session依賴cookie
    • 可記錄的數據量較大,數據相對安全

使用 session

​ 使用 django-admin startproject 創建的項目默認啟用,啟用會話后,每個 HttpResponse 對象將具有一個 session 屬性,session 是一個類字典對象

# 添加數據
request.session['key'] = value

# 獲取數據
request.session.get('key',default=Node)

# 刪除數據
del request.session['key']

# 清除所有會話,不會刪除數據
rquest.session.clear()

# 刪除當前的會話數據
request.session.flush()

中間件

​ 中間件是介於請求和響應之間的一個組件,用於全局更改 Django 的輸入(請求)或輸出(響應),可以對請求或響應進行攔截、篩選、過濾等處理,如CSRF中間件

​ get_response 就是需要響應的內容,可能是視圖,也可能是下一個中間,但當前的中間件不需要知道它到底是什么,只要知道它代表接下來發生的事即可

激活中間件

​ 自定義的中間件需要把自定義類配置在 settings 下的 MIDDLEWARE 中才會生效,格式為:' 包名.模塊名.類名 '


驗證碼

​ 注冊、登陸頁面,為了防止暴力請求可以加入驗證碼功能,如果驗證碼錯誤,則不需要繼續處理,以減輕服務器壓力

​ 使用驗證碼也是一種有效防止CSRF的方法

驗證碼視圖

  • 導入 PIL 中的 image、imageDraw、imageFont 模塊,分別為畫布對象、畫筆對象、字體對象
  • 定義生成驗證碼的函數 verifycode
  • 配置驗證碼函數的url,並在模板中調用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM