前言
本項目是使用三段分離的設計
前臺
使用materialize框架搭建的前臺頁面,后端使用的django寫的接口
后臺
使用Amazon UI 模板搭建的界面,管理各個部分的內容
項目環境
python3.7.2
django2.2.9
vue
axios
jQuery
materialize
mysql
摘 要
本設計采用前后端分離的設計模式,前端通過vue的axios發送ajax請求來調用后端接口,實現頁面的展示,后端使用Python中的django框架來訪問數據庫,并返回json數據。django是一個完整的開源web開源框架,使用起來能夠快速的搭建你想要的網站。本設計中后臺管理模板采用amazeUI頁面的樣式實現。數據庫部分采用開源的mysql數據庫,由于django操作數據庫很方便,所以我們只需要關心框架中的models類的設計即可,只需要關心視圖邏輯,后臺管理系統即可實現基本的增刪改查功能。
關鍵詞:Python;Vue;Django;ajax;Mysql;
1. 基礎環境的簡介
1.1 Python介紹。
Python是一種跨平臺的計算機程序設計語言。是一種面向對象的動態類型語言,最初被設計用于編寫自動化腳本(shell),隨著版本的不斷更新和語言新功能的添加,越來越多被用于獨立的、大型項目的開發。
Python的設計哲學是“優雅”、“明確”、“簡單”。因此,Perl語言中“總是有多種方法來做同一件事”的理念在Python開發者中通常是難以忍受的。Python開發者的哲學是“用一種方法,最好是只有一種方法來做一件事”。在設計Python語言時,如果面臨多種選擇,Python開發者一般會拒絕花俏的語法,而選擇明確的沒有或者很少有歧義的語法。由于這種設計觀念的差異,Python源代碼通常被認為比Perl具備更好的可讀性,并且能夠支撐大規模的軟件開發。這些準則被稱為Python格言。在Python解釋器內運行import this可以獲得完整的列表。Python是完全面向對象的語言。函數、模塊、數字、字符串都是對象。并且完全支持繼承、重載、派生、多繼承,有益于增強源代碼的復用性。
1.2 Python 特點
1.易于學習
Python有相對較少的關鍵字,結構簡單,學習起來更加簡單。
2.易于閱讀
Python代碼定義的更清晰。
3.易于維護
Python的成功在于它的源代碼是相當容易維護的。
4.一個廣泛的標準庫
Python的最大的優勢之一是豐富的庫,跨平臺的,兼容很好。
5.互動模式
您可以從終端輸入執行代碼并獲得結果的語言,互動的測試和調試代碼片斷。
6.可移植
基于其開放源代碼的特性,Python已經被移植(也就是使其工作)到許多平臺。
7.可擴展
如果你需要一段運行很快的關鍵代碼,或者是想要編寫一些不愿開放的算法,你可以使用C或C++完成那部分程序,然后從你的Python程序中調用。
8.數據庫
Python提供所有主要的商業數據庫的接口。
9.GUI編程
Python支持GUI可以創建和移植到許多系統調用。
10.可嵌入
你可以將Python嵌入到C/C++程序,讓你的程序的用戶獲得"腳本化"的能力。
1.3 Django介紹
Django 是一個高級的 Python 網絡框架,可以快速開發安全和可維護的網站。由經驗豐富的開發者構建,Django負責處理網站開發中麻煩的部分,因此你可以專注于編寫應用程序,而無需重新開發。
它是免費和開源的,有活躍繁榮的社區,豐富的文檔,以及很多免費和付費的解決方案。
1.3.1 完備性
Django遵循“功能完備”的理念,提供開發人員可能想要“開箱即用”的幾乎所有功能。因為你需要的一切都是一個”產品“的一部分,它們都可以無縫結合在一起,遵循一致性設計原則,并且具有廣泛和最新的文檔.
1.3.2 通用性
Django 可以(并已經)用于構建幾乎任何類型的網站—從內容管理系統和維基,到社交網絡和新聞網站。它可以與任何客戶端框架一起工作,并且可以提供幾乎任何格式(包括 HTML,Rss源,JSON,XML等)的內容。你正在閱讀的網站就是基于Django。
在內部,盡管它為幾乎所有可能需要的功能(例如幾個流行的數據庫,模版引擎等)提供了選擇,但是如果需要,它也可以擴展到使用其他組件。
1.3.3 安全性
Django 幫助開發人員通過提供一個被設計為“做正確的事情”來自動保護網站的框架來避免許多常見的安全錯誤。例如,Django提供了一種安全的方式來管理用戶賬戶和密碼,避免了常見的錯誤,比如將session放在cookie中這種易受攻擊的做法(取而代之的是cookies只包含一個密鑰,實際數據存儲在數據庫中)或直接存儲密碼而不是密碼哈希。
1.3.4 可擴展
Django 使用基于組件的 “無共享” 架構 (架構的每一部分獨立于其他架構,因此可以根據需要進行替換或更改). 在不用部分之間有明確的分隔意味著它可以通過在任何級別添加硬件來擴展服務:緩存服務器,數據庫服務器或應用程序服務器。一些最繁忙的網站已經成功地縮放了Django,以滿足他們的需求(例如Instagram和Disqus,僅舉兩個例子,可自行添加)。
1.3.5 可維護性
Django 代碼編寫是遵照設計原則和模式,鼓勵創建可維護和可重復使用的代碼。特別是它使用了不要重復自己(DRY)原則,所以沒有不必要的重復,減少了代碼的數量。Django還將相關功能分組到可重用的“應用程序”中,并且在較低級別將相關代碼分組或模塊( 模型視圖控制器 (MVC) 模式).
1.3.6 靈活性
Django 是用Python編寫的,它在許多平臺上運行。這意味著你不受任務特定的服務器平臺的限制,并且可以在許多種類的Linux,Windows和Mac OsX 上運行應用程序。此外,Django得到許多網絡托管提供商的好評,他們經常提供特定的基礎設施和托管Django網站的文檔。
1.4 Mysql介紹
MySQL 是一個關系型數據庫管理系統,由瑞典 MySQL AB 公司開發,目前屬于 Oracle 公司。
MySQL 使用的 SQL 語言是用于訪問數據庫的最常用的標準化語言。
由于 MySQL 數據庫體積小、速度快、總體擁有成本低、開放源代碼,其有著廣泛的應用,一般中小型網站的開發都選擇 MySQL 作為網站數據庫。由于其社區版的性能卓越,因此搭配 PHP 和 Apache 服務器可組成良好的開發環境。
2. 需求分析
建站包括前臺功能系統和后臺管理系統兩大系統組成,分別由不同能力的人 員實現,而前臺功能系統是屬于 UI 設計類的,后臺管理系統是程序類的,因此 本設計選擇進行后臺管理系統設計。 由于本設計是后臺管理系統,主要功能是對前臺展示的頁面進行增刪改查的操作。
本站主要的功能是作為信息的展示和宣傳,大體上分為4個頁面:首頁,課程頁,教學特色頁和學員風采頁。主要功能如下圖所示:
圖2.1 XDH官網需求分析圖
2.1 首頁
首頁主要分為以下幾部分:
(1)輪播圖
(2)兄弟會介紹
(3)兄弟會與傳統就業班區別
(4)師資力量
(5)就業喜報
(6)學科介紹
2.2 課程介紹
(1)培訓課程,具體學科介紹
(2)兄弟會具體學科及分級介紹
(3)兄弟會解決了什么問題
(4)重點突出兄弟會課程體系與傳統培訓體系的不同
(5)學習的苦VS生活的苦(不吃學習的苦就要吃生活的苦)
2.3 教學特色
(1)辦學理念-具有真實交付能力的程序員
(2)項目驅動式學習-每階段都有可鍛煉的項目
(3)企業級項目經理指導
(4)真實的企業級商業項目全程開發
(5)學習經驗分享
(6)企業文化培訓(培養身心健康的程序員)
2.4 學員風采
(1)學員采訪視頻
(2)學員感言
(3)個人博客
(4)團建活動
(5)我們的作品
3. Django模型model類的設計
模型設計是整個項目的核心部分,直接決定了項目后續的可行性,這里我們分為兩個 app 來進行設計,分別為api和bgapi,一個作為前臺的接口,一個是進行后臺管理的接口。
3.1 導入所需模塊
from django.db import models
from django.utils import timezone
3.2 所有輪播圖
class Banner(models.Model):img = models.TextField()page = models.CharField(max_length=20)link = models.CharField(max_length=100)is_del = models.IntegerField(default=0)join_date = models.DateTimeField(default=timezone.now)
3.3 工作信息表
class JobInfo(models.Model):major = models.CharField(max_length=50,default="") # 專業major 主修,專業 (專指大學)school = models.CharField(max_length=50)name = models.CharField(max_length=20)title = models.CharField(max_length=50)img = models.CharField(max_length=200)salary = models.CharField(max_length=20)date = models.DateField()is_del = models.IntegerField(default=0)join_date = models.DateTimeField(default=timezone.now)
3.4 學員感言
class StudentSay(models.Model):img = models.CharField(max_length=50) # 頭像圖片 avator是頭像的意思name = models.CharField(max_length=20)title = models.CharField(max_length=255)content = models.TextField()is_del = models.IntegerField(default=0)join_date = models.DateTimeField(default=timezone.now)
3.5 技術社區內容
class Community(models.Model):subject = models.CharField(max_length=50)type = models.CharField(max_length=50)content = models.TextField()link = models.TextField()is_del = models.IntegerField(default=0)
3.6 辦學特色
class Feature(models.Model):img = models.CharField(max_length=250)title = models.CharField(max_length=250)type = models.CharField(max_length=250)content = models.TextField()is_del = models.IntegerField(default=0)join_date = models.DateTimeField(default=timezone.now)
3.7 課程內容
class Source(models.Model):text = models.CharField(max_length=150)link = models.CharField(max_length=250)is_del = models.IntegerField(default=0)join_date = models.DateTimeField(default=timezone.now)
3.8 個人博客
class Blog(models.Model):name = models.CharField(max_length=20)link = models.CharField(max_length=100)img = models.CharField(max_length=255)title = models.CharField(max_length=255)description = models.TextField()is_del = models.IntegerField(default=0)join_date = models.DateTimeField(default=timezone.now)
3.9 用于登錄token表
class Token(models.Model):token_data = models.CharField(max_length=250)token_key = models.CharField(max_length=250)change_time = models.DateTimeField('最后修改日期',auto_now=True)
4. view視圖函數
視圖函數是本項目的核心,主要負責收到前端ajax的請求,進行初步的處理,然后去數據庫中進行增刪改查操作,并返回JSON格式的數據給請求方。具體的代碼可參考附錄II
5. 接口文檔
前后臺分離后,他們兩端之間的通訊是通過前臺調用后臺的接口實現的,所以一份清晰明了的接口文檔會增加項目開發的效率,本項目的接口文檔如附錄中所示,其中包含了接口名稱、 接口url、請求方法和請求參數。
6. 部署上線
6.1 域名
本項目上線前需要購買一個域名,并進行域名的解析,在域名解析前需要先進行網站的備案,只有備案后才能將域名綁定在相應的服務器上面
6.2 服務器
本項目的后臺采用的是阿里云服務器,使用寶塔工具連接遠程服務器,對服務器和數據庫進行管理,寶塔Linux面板是提升運維效率的服務器管理軟件,支持一鍵LAMP/LNMP/集群/監控/網站/FTP/數據庫/JAVA等100多項服務器管理功能。
有20個人的專業團隊研發及維護,經過200多個版本的迭代,功能全,少出錯且足夠安全,已獲得全球百萬用戶認可安裝。
6.3 數據庫
本項目的數據庫使用的是mysql5.7版本,由于mysql具有開源免費等優點,加上寶塔工具的控制,進行數據庫的部署也十分的方便。
7. 項目總結
本項目通過采用前后端分離的方式來進行設計,能夠分離減少各個項目部分之間的耦合性,一方面有利于將項目不同的部分分配給擅長不同領域的開發人員進行開發,另一方面,可以增加后期項目的可維護性。
整個項目用時一周,雖然其中有很多的漏洞,但是在做完整個項目后還是收獲了很多的,這能夠為以后的學習和工作增添一些經歷和項目經驗吧。
參考文獻
[1] Django項目實例精解(第2版)作者:[美]安東尼奧米勒 清華大學出版社
[2] Python Web開發實戰 作者:董偉明著 出版社:電子工業出版社
[3] MySQL 5.7從入門到精通(視頻教學版)(第2版)張工廠 清華大學出版社
[4] Python Django Web典型模塊開發實戰 作者:寇雪松 出版社:機械工業出版社
附錄
附錄I 接口文檔
后臺 接口名稱 接口url 請求方法 請求參數
登錄 用于管理員登錄 /bgapi/login/ post請求 username獲取驗證碼 /bgapi/verification/
博客 列表 /bgapi/blog/list/ get請求
博客
社區資源 添加 /bgapi/blog/add/ post請求 name=file修改 /bgapi/blog/edit/ post請求 name=file刪除 /bgapi/blog/del/ get請求 ?id=1列表 /bgapi/community/list/ get請求
社區資源
輪播圖 添加 /bgapi/community/add/ post請求 subject,修改 /bgapi/community/edit/ post請求 id,subject,刪除 /bgapi/community/delete/ get請求 id列表 /bgapi/banner/list/ get請求 啥也不用
輪播圖
學生視頻 添加 /bgapi/banner/add/ post請求 name=file修改 /bgapi/banner/edit/ post請求 name=file刪除 /bgapi/banner/del/ get請求 id列表 /bgapi/assessvideo/list/ get請求
學生視頻
辦學特色 添加 /bgapi/assessvideo/add/ post請求 video,img修改 /bgapi/assessvideo/edit/ post請求 video,img刪除 /bgapi/assessvideo/delete/ get請求 id列表 /bgapi/feature/list/ get請求
辦學特色
首頁信息 添加 /bgapi/feature/add/ post請求 name=file修改 /bgapi/feature/edit/ post請求 name=file刪除 /bgapi/feature/delete/ get請求 id列表 /bgapi/mainpuretext/list/ get請求
首頁信息
首頁學科 添加 /bgapi/mainpuretext/add/ post請求 title,content修改 /bgapi/mainpuretext/edit/ post請求 id,title,content刪除 /bgapi/mainpuretext/delete/ get請求 id列表 /bgapi/mainsubject/list/ get請求
首頁學科
階段管理 添加 /bgapi/mainsubject/add/ post請求 name=file修改 /bgapi/mainsubject/edit/ post請求 name=file刪除 /bgapi/mainsubject/delete/ get請求 id列表 /bgapi/stage/list/ get請求
階段管理
學員感言 添加 /bgapi/stage/add/ post請求 name=file修改 /bgapi/stage/edit/ post請求 name=file刪除 /bgapi/stage/delete/ get請求 id列表 /bgapi/studentsay/list/ get請求
學員感言
學員作品 添加 /bgapi/studentsay/add/ post請求 name=file修改 /bgapi/studentsay/edit/ post請求 name=file刪除 /bgapi/studentsay/delete/ get請求 id列表 /bgapi/studentworks/list/ get請求
學員作品
工作信息 添加 /bgapi/studentworks/add/ post請求 name=file修改 /bgapi/studentworks/edit/ post請求 name=file刪除 /bgapi/studentworks/delete/ get請求 id列表 /bgapi/jobinfo/list/ get請求
工作信息
教師信息 添加 /bgapi/jobinfo/add/ post請求 name=file修改 /bgapi/jobinfo/edit/ post請求 name=file刪除 /bgapi/jobinfo/delete/ get請求 id列表 /bgapi/teacher/list/ get請求
教師信息
課程詳情 添加 /bgapi/teacher/add/ post請求 name=file修改 /bgapi/teacher/edit/ post請求 name=file刪除 /bgapi/teacher/delete/ get請求 id列表 /bgapi/coursedetail/list/ get請求
課程詳情
活動管理 添加 /bgapi/coursedetail/add/ post請求 name=file修改 /bgapi/coursedetail/edit/ post請求 name=file刪除 /bgapi/coursedetail/delete/ get請求 id列表 /bgapi/activity/list/ get請求
活動管理 添加 /bgapi/activity/add/ post請求 name=file修改 /bgapi/activity/edit/ post請求 name=file刪除 /bgapi/activity/delete/ get請求 id
附錄II:視圖函數程序代碼
課程管理視圖函數
from django.forms import model_to_dict
from django.shortcuts import render
from django.http import JsonResponse,HttpResponsefrom api.models import CourseDetail,Token
from django.conf import settingsfrom .utils import add_data,edit_data,delete_data,list_data,check_token,check_md5def list(request):if check_token(request):passelse:u_dict = {"status": "509","info": "請先登錄!",}return JsonResponse(u_dict)'''列表顯示視圖函數:param request:請求參數:return:返回json格式數據'''# # 驗證是否登錄# if check_token(request):# # 如果成了# pass# else:# u_dict = {# "status": "509",# "info": "請先登錄!",# }# return JsonResponse(u_dict)# 驗證完了u_dict = list_data(CourseDetail)response = JsonResponse(u_dict)return responsedef add(request):# 驗證是否登錄if check_md5(request):# 如果成了passelse:u_dict = {"status": "509","info": "請先登錄!",}return JsonResponse(u_dict)# 驗證完了'''添加視圖函數:param request:請求參數:return:返回json格式數據'''u_dict = add_data(request,CourseDetail)return JsonResponse(u_dict)def edit(request):# 驗證是否登錄if check_md5(request):# 如果成了passelse:u_dict = {"status": "509","info": "請先登錄!",}return JsonResponse(u_dict)# 驗證完了'''編輯視圖函數:param request:請求參數:return:返回json格式數據'''u_dict = edit_data(request,CourseDetail)return JsonResponse(u_dict)def delete(request):# 驗證是否登錄if check_token(request):# 如果成了passelse:u_dict = {"status": "509","info": "請先登錄!",}return JsonResponse(u_dict)# 驗證完了'''刪除視圖函數:param request:請求參數:return:返回json格式數據'''u_dict = delete_data(request,CourseDetail)return JsonResponse(u_dict)
封裝工具類
保存文件
def save_file(file):'''用于保存文件,返回保存文件的路徑:param file::return:'''if file:# 上傳了頭像import hashlib# 待加密信息(隨機數)ran_str = str(random.randint(0, 9999999))# 創建md5對象hl = hashlib.md5()to_md5_str = str(time()) + ran_str# Tips# 此處必須聲明encode# 若寫法為hl.update(str) 報錯為: Unicode-objects must be encoded before hashinghl.update(to_md5_str.encode(encoding='utf-8'))# 加密完的md5字符串md5_str = hl.hexdigest()# 文件擴展名file_extend_name = file.name.split('.').pop()# 拼接文件名filename = md5_str + '.' + file_extend_namewith open(f'./media/' + filename, 'wb+') as f:f.write(file.read())# with open(f'./media/uploads/' + filename, 'wb+') as fp:# fp.write(file.read())return filenameelse:return ""刪除文件
def del_file(path):'''用于刪除文件,返回刪沒刪成功:param path::return:'''import osmy_file = settings.BASE_DIR + settings.MEDIA_URL + pathprint(my_file)if os.path.exists(my_file):# 刪除文件,可使用以下兩種方法。os.remove(my_file)return Trueelse:return False成功返回數據
def success_response(u_dict):'''正確返回數據 過濾器:param u_dict: 返回的數據主體內容:return: 嵌套后的數據'''u_dict = {"status": "200","info": "返回信息成功!","data": u_dict}return u_dict返回錯誤信息
def error_response(u_dict, err_info):'''返回錯誤json:param u_dict: json返回的主要內容:param err_info: 錯誤提示信息:return:'''u_dict = {"status": "500","info": err_info,"data": u_dict}return u_dict查詢數據
def list_data(a_model_object):'''用于列表返回所有數據庫數據:param a_model_object: 一個模型對象:return: 返回json數據格式的字典dict類型數據'''print("--------------------------開始列表視圖函數---------------------------")u_dict = {}try:u_dict = all_data(a_model_object)# 嵌套一層u_dict = success_response(u_dict)except:u_dict = error_response(u_dict, "服務器錯誤,查詢異常!")return u_dict
添加數據
def add_data(request, a_model_object):'''封裝的添加方法:param request: http的請求request參數:param a_model_object: 一個模型對象:return: 返回json之前的字典類型的數據'''print("--------------------------開始添加視圖函數---------------------------")# 定義返回數據u_dict = {}# 判斷請求方式if (request.method == 'POST'):# try:# 開始處理圖片# 1.獲取表單內容data = request.POST.dict()print(data)# 要是有link,那就判斷一下是不是真的linkif "link" in data.keys():curr_link = data["link"]if check_link(curr_link):# 要是鏈接,啥也不干passelse:# 要是不行,那直接就給踢回去u_dict = {"info": "鏈接類型不正確,請檢查格式!","status": "506"}return u_dict# 先刪除tokendata.pop("token")# 2. 獲取表單中的文件file = request.FILES.get('file', None)print("file", file)# 3. 執行保存文件,并返回文件路徑# save_file ---> 自定義函數path = save_file(file)# TODO 這里判斷文件類型try:kind = filetype.guess(settings.BASE_DIR+settings.MEDIA_URL+path)print("猜出來的類型是:",kind)print("猜出來的類型extension是:",kind.extension)print("猜出來的類型mime是:",kind.mime)# TODO: write code.....# # 判斷真的文件類型if kind.extension == "png" or kind.extension == "jpg":# 要是符合類型的,啥也不干passelse:# 要不是這倆類型# 直接我就返回,錯誤信息u_dict = {"info": "圖片類型不正確,請上傳png或者jpg格式!","status": "505"}return u_dictexcept:u_dict = {"info": "圖片類型不正確,請上傳png或者jpg格式!","status": "505"}return u_dictif not path:data.pop("file")# 構建img字段數據data["img"] = path# data.pop("file")# 保存數據a_model_object(**data).save()# 返回數據內容u_dict = {"info": "ok","status": "200"}# except:# u_dict = {# "info": "error",# "status": "500"# }if (request.method == 'GET'):u_dict = {"info": "缺心眼啊,用瀏覽器訪問!","status": "666"}return u_dict
修改數據
def edit_data(request, a_model_object):'''用于編輯的封裝函數:param request: 一個請求的參數:param a_model_object: 一個模型類對象:return: 返回提示信息的json格式字典dict'''print("--------------------------開始編輯視圖函數---------------------------")u_dict = {}print("request.POST:", request.POST)print("request.FILES:", request.FILES)if (request.method == 'POST'):# 獲取修改的iddata = request.POST.dict()print(data)# 先刪除tokendata.pop("token")# 要是有link,那就判斷一下是不是真的linkif "link" in data.keys():curr_link = data["link"]if check_link(curr_link):# 要是鏈接,啥也不干passelse:# 要是不行,那直接就給踢回去u_dict = {"info": "鏈接類型不正確,請檢查格式!","status": "506"}return u_dict# print(data.__dict__)id = data["id"]# 獲取原來的對象obj = a_model_object.objects.get(id=id)dict = model_to_dict(obj)old_path = dict['img']# 2. 獲取表單中的文件new_file = request.FILES.get('file', None)# 判斷有沒有新文件print("new_file:", new_file)# 要是有新文件的話if new_file:# print(new_file)# print(type(new_file))# print("走的有文件")# 刪除舊文件del_file(old_path)# 保存新文件path = save_file(new_file)print("new_path:", path)# 構建img字段數據data["img"] = pathelse:# print("走的沒文件")# print(new_file)# print(type(new_file))# 沒有新文件data["img"] = old_pathdata.pop("file")obj = a_model_object.objects.filter(id=id)obj.update(**data)# else:# u_dict = {# "info": "刪除文件失敗!",# "status": "501"# }# return JsonResponse(u_dict)# 成功狀態碼u_dict = {"info": "ok","status": "200"}if (request.method == 'GET'):# 請求方式不對狀態碼u_dict = {"info": "no","status": "666"}return u_dict
刪除數據
def delete_data(request, a_model_object):'''用于刪除封裝的方法:param request: 一個請求參數:param a_model_object: 一個模型對象:return: 返回json類型的字典數據'''u_dict = {"info": "default","status": "888"}print("--------------------------開始刪除視圖函數---------------------------")try:# 嘗試刪除id = request.GET.get("id")obj = a_model_object.objects.get(id=id)# 刪除源文件# 獲取文件路徑dict = model_to_dict(obj)# 刪除庫obj.delete()# 原始路徑old_path = dict['img']print("old_path:", old_path)# 執行刪除del_file(old_path)u_dict = {"info": "ok","status": "200"}except:u_dict = {"info": "error","status": "500"}return u_dict