基於前面兩個章節講解的知識,咱們已經可使用Django框架來實現Web應用的開發了。接下來咱們就嘗試實現一個投票應用,具體的需求是用戶進入應用首先查看到「學科介紹」頁面,該頁面顯示了一個學校所開設的全部學科;經過點擊某個學科,能夠進入「老師介紹」頁面,該頁面展現了該學科全部老師的詳細狀況,能夠在該頁面上給老師點擊「好評」或「差評」,可是會先跳轉到「登陸頁」要求用戶登陸,登陸成功才能投票;對於未註冊的用戶,能夠在「登陸頁」點擊「新用戶註冊」進入「註冊頁」完成用戶註冊,註冊成功後會跳轉到「登陸頁」,註冊失敗會得到相應的提示信息。css
因爲以前已經詳細的講解了如何建立Django項目以及項目的相關配置,所以咱們略過這部份內容,惟一須要說明的是,從上面對投票應用需求的描述中咱們能夠分析出三個業務實體:學科、老師和用戶。學科和老師之間一般是一對多關聯關係(一個學科有多個老師,一個老師一般只屬於一個學科),用戶由於要給老師投票,因此跟老師之間是多對多關聯關係(一個用戶能夠給多個老師投票,一個老師也能夠收到多個用戶的投票)。首先修改應用下的models.py文件來定義數據模型,先給出學科和老師的模型。html
from django.db import models class Subject(models.Model): """學科""" no = models.AutoField(primary_key=True, verbose_name='編號') name = models.CharField(max_length=31, verbose_name='名稱') intro = models.CharField(max_length=511, verbose_name='介紹') def __str__(self): return self.name class Meta: db_table = 'tb_subject' verbose_name_plural = '學科' class Teacher(models.Model): """老師""" no = models.AutoField(primary_key=True, verbose_name='編號') name = models.CharField(max_length=15, verbose_name='姓名') gender = models.BooleanField(default=True, choices=((True, '男'), (False, '女')), verbose_name='性別') birth = models.DateField(null=True, verbose_name='出生日期') intro = models.CharField(max_length=511, default='', verbose_name='') good_count = models.IntegerField(default=0, verbose_name='好評數') bad_count = models.IntegerField(default=0, verbose_name='差評數') photo = models.CharField(max_length=255, verbose_name='照片') subject = models.ForeignKey(to=Subject, on_delete=models.PROTECT, db_column='sno', verbose_name='所屬學科') def __str__(self): return self.name class Meta: db_table = 'tb_teacher' verbose_name_plural = '老師'
模型定義完成後,能夠經過「生成遷移」和「執行遷移」來完成關係型數據庫中二維表的建立,固然這須要提早啓動數據庫服務器並建立好對應的數據庫,同時咱們在項目中已經安裝了PyMySQL並且完成了相應的配置,這些內容此處再也不贅述。前端
(venv)$ python manage.py makemigrations vote
...
(venv)$ python manage.py migrate
...
注意:爲了給vote應用生成遷移,須要先修改Django項目的配置文件settings.py,在INSTALLED_APPS中添加vote應用。python
完成模型遷移以後,咱們能夠經過下面的SQL語句來添加學科和老師測試的數據。jquery
INSERT INTO `tb_subject` (`no`,`name`,`intro`) VALUES (1, 'Python全棧+人工智能', 'Python是一種面向對象的解釋型計算機程序設計語言,由荷蘭人Guido van Rossum於1989年發明,第一個公開發行版發行於1991年。'), (2, 'JavaEE+分佈式服務', 'Java是一門面向對象編程語言,不只吸取了C++語言的各類優勢,還摒棄了C++裏難以理解的多繼承、指針等概念,所以Java語言具備功能強大和簡單易用兩個特徵。'), (3, 'HTML5大前端', 'HTML5 將成爲 HTML、XHTML 以及 HTML DOM 的新標準。'), (4, '全棧軟件測試', '在規定的條件下對程序進行操做,以發現程序錯誤,衡量軟件質量,並對其是否能知足設計要求進行評估的過程'), (5, '全鏈路UI/UE', '全鏈路要求設計師關注整個業務鏈中的每個環節,將設計的價值融入每個和用戶的接觸點中,讓整個業務的用戶體驗質量獲得幾何級數的增加。'); INSERT INTO `tb_teacher` (`no`,`name`,`gender`,`birth`,`intro`,`good_count`,`bad_count`,`photo`,`sno`) VALUES (1, '駱昊', 1, '1980-11-28', '10年以上軟硬件產品設計、研發、架構和管理經驗,2003年畢業於四川大學,四川大學Java技術俱樂部創始人,四川省優秀大學畢業生,在四川省網絡通訊技術重點實驗室工做期間,參與了2項國家天然科學基金項目、1項中國科學院中長期研究項目和多項四川省科技攻關項目,在國際會議和國內頂級期刊上發表多篇論文(1篇被SCI收錄,3篇被EI收錄),大規模網絡性能測量系統DMC-TS的設計者和開發者,perf-TTCN語言的發明者。國內最大程序員社區CSDN的博客專家,在Github上參與和維護了多個高質量開源項目,精通C/C++、Java、Python、R、Swift、JavaScript等編程語言,擅長OOAD、系統架構、算法設計、協議分析和網絡測量,主持和參與過電子政務系統、KPI考覈系統、P2P借貸平臺等產品的研發,一直踐行「用知識創造快樂」的教學理念,善於總結,樂於分享。', 0, 0, 'images/luohao.png', 1), (2, '王海飛', 1, '1993-05-24', '5年以上Python開發經驗,前後參與了O2O商城、CRM系統、CMS平臺、ERP系統等項目的設計與研發,曾在全國最大最專業的汽車領域相關服務網站擔任Python高級研發工程師、項目經理等職務,擅長基於Python、Java、PHP等開發語言的企業級應用開發,全程參與了多個企業級應用從需求到上線所涉及的各類工做,精通Django、Flask等框架,熟悉基於微服務的企業級項目開發,擁有豐富的項目實戰經驗。善於用淺顯易懂的方式在課堂上傳授知識點,在授課過程當中常常穿插企業開發的實際案例並分析其中的重點和難點,經過這種互動性極強的教學模式幫助學員找到解決問題的辦法並提高學員的綜合素質。', 0, 0, 'images/wangdachui.png', 1), (3, '餘婷', 0, '1992-03-12', '5年以上移動互聯網項目開發經驗和教學經驗,曾擔任上市遊戲公司高級軟件研發工程師和移動端(iOS)技術負責人,參了多個企業級應用和遊戲類應用的移動端開發和後臺服務器開發,擁有豐富的開發經驗和項目管理經驗,以我的開發者和協做開發者的身份在蘋果的AppStore上發佈過多款App。精通Python、C、Objective-C、Swift等開發語言,熟悉iOS原生App開發、RESTful接口設計以及基於Cocos2d-x的遊戲開發。授課條理清晰、細緻入微,性格活潑開朗、有較強的親和力,教學過程注重理論和實踐的結合,在學員中有良好的口碑。', 0, 0, 'images/yuting.png', 1), (4, '肖世榮', 1, '1977-07-02', '10年以上互聯網和移動互聯網產品設計、研發、技術架構和項目管理經驗,曾在中國移動、symbio、ajinga.com、萬達信息等公司擔任架構師、項目經理、技術總監等職務,長期爲蘋果、保時捷、耐克、沃爾瑪等國際客戶以及國內的政府機構提供信息化服務,主導的項目曾得到「世界科技先鋒」稱號,我的做品「許願吧」曾在騰訊應用市場生活類App排名前3,擁有百萬級用戶羣體,運營的公衆號「卵石坊」是國內知名的智能穿戴設備平臺。精通Python、C++、Java、Ruby、JavaScript等開發語言,主導和參與了20多個企業級項目(含國家級重大項目和互聯網創新項目),涉及的領域包括政務、社交、電信、衛生和金融,有極爲豐富的項目實戰經驗。授課深刻淺出、條理清晰,善於調動學員的學習熱情並幫助學員理清思路和方法。', 0, 0, 'images/xiaoshirong.png', 1), (5, '張無忌', 1, '1987-07-07', '出生起便在冰火島過着原始生活,踏入中土後因中玄冥神掌命危而帶病習醫,忍受寒毒煎熬七年最後因福緣際會練成「九陽神功」更在以後又練成了「乾坤大挪移」等蓋世武功,幾乎無敵於天下。 生性隨和,宅心仁厚,精通醫術和藥理。20歲時便憑着蓋世神功當上明教教主,率領百萬教衆及武林羣雄反抗蒙古政權元朝的高壓統治,最後推翻了元朝。因爲擅長乾坤大挪移神功,上課遇到問題就轉移話題,屬於拉不出屎怪地球沒有引力的類型。', 0, 0, 'images/zhangwuji.png', 5), (6, '韋一笑', 1, '1975-12-15', '外號「青翼蝠王」,爲明教四大護教法王之一。 身披青條子白色長袍,輕功十分了得。因爲在修煉至陰至寒的「寒冰綿掌」時出了差錯,經脈中鬱積了至寒陰毒,只要運上內力,寒毒就會發做,若是不吸人血解毒,全身血脈就會凝結成冰,後得張無忌相助,以其高明醫術配以「九陽神功」,終將寒毒驅去,擺脫了吸吮人血這一命運。因爲輕功絕頂,學生一問問題就跑了。', 0, 0, 'images/weiyixiao.png', 3);
固然也能夠直接使用Django提供的後臺管理應用來添加學科和老師信息,這須要先註冊模型類和模型管理類。git
from django.contrib import admin from django.contrib.admin import ModelAdmin from vote.models import Teacher, Subject class SubjectModelAdmin(ModelAdmin): """學科模型管理""" list_display = ('no', 'name') ordering = ('no', ) class TeacherModelAdmin(ModelAdmin): """老師模型管理""" list_display = ('no', 'name', 'gender', 'birth', 'good_count', 'bad_count', 'subject') ordering = ('no', ) search_fields = ('name', ) admin.site.register(Subject, SubjectModelAdmin) admin.site.register(Teacher, TeacherModelAdmin)
接下來,咱們就能夠修改views.py文件,經過編寫視圖函數先實現「學科介紹」頁面。程序員
def show_subjects(request): """查看全部學科""" subjects = Subject.objects.all() return render(request, 'subject.html', {'subjects': subjects})
至此,咱們還須要一個模板頁,模板的配置以及模板頁中模板語言的用法在以前已經進行過簡要的介紹,若是不熟悉能夠看看下面的代碼,相信這並非一件困難的事情。github
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>學科信息</title> <style>/* 此處略去了層疊樣式表的選擇器 */</style> </head> <body> <h1>千鋒互聯全部學科信息</h1> <hr> <div id="container"> {% for subject in subjects %} <dl> <dt> <a href="/teachers?sno={{ subject.no }}"> {{ subject.name }} </a> </dt> <dd>{{ subject.intro }}</dd> </dl> {% endfor %} </div> </body> </html>
在上面的模板中,咱們爲每一個學科添加了一個超連接,點擊超連接能夠查看該學科的講師信息,爲此須要再編寫一個視圖函數來處理查看指定學科老師信息。ajax
def show_teachers(request): """查看指定學科的老師""" try: sno = int(request.GET['sno']) subject = Subject.objects.get(no=sno) teachers = Teacher.objects.filter(subject__no=sno) context = {'subject': subject, 'teachers': teachers} return render(request, 'teacher.html', context) except (KeyError, ValueError, Subject.DoesNotExist): return redirect('/')
顯示老師信息的模板頁。算法
<!DOCTYPE html>
{% load static %}
<html lang="en"> <head> <meta charset="UTF-8"> <title>老師信息</title> <style>/* 此處略去了層疊樣式表的選擇器 */</style> </head> <body> <h1>{{ subject.name }}學科老師信息</h1> <hr> {% if teachers %} <div id="container"> {% for teacher in teachers %} <div class="teacher"> <div class="photo"> <img src="{% static teacher.photo %}" height="140" alt=""> </div> <div class="info"> <div> <span><strong>姓名:{{ teacher.name }}</strong></span> <span>性別:{{ teacher.gender | yesno:'男,女' }}</span> <span>出生日期:{{ teacher.birth }}</span> </div> <div class="intro">{{ teacher.intro }}</div> <div class="comment"> <a href="">好評({{ teacher.good_count }})</a> <a href="">差評({{ teacher.bad_count }})</a> </div> </div> </div> {% endfor %} </div> {% else %} <h2>暫時沒有該學科的老師信息</h2> {% endif %} <div class="back"> <a href="/"><< 返回學科</a> </div> </body> </html>
在上面的模板頁面中,咱們使用了<img>
標籤來加載老師的照片,其中使用了引用靜態資源的模板指令{% static %}
,要使用該指令,首先要使用{% load static %}
指令來加載靜態資源,咱們將這段代碼放在了頁碼開始的位置。在上面的項目中,咱們將靜態資源置於名爲static的文件夾中,在該文件夾下又建立了三個文件夾:css、js和images,分別用來保存外部層疊樣式表、外部JavaScript文件和圖片資源。爲了可以找到保存靜態資源的文件夾,咱們還須要修改Django項目的配置文件settings.py,以下所示:
# 此處省略上面的代碼 STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] STATIC_URL = '/static/' # 此處省略下面的代碼
接下來修改urls.py文件,配置用戶請求的URL和視圖函數的對應關係。
from django.contrib import admin from django.urls import path from vote import views urlpatterns = [ path('', views.show_subjects), path('teachers/', views.show_teachers), path('admin/', admin.site.urls), ]
啓動服務器運行項目,進入首頁查看學科信息。
點擊學科查看老師信息。
接下來就能夠實現「好評」和「差評」的功能了,很明顯若是可以在不刷新頁面的狀況下實現這兩個功能會帶來更好的用戶體驗,所以咱們考慮使用Ajax技術來實現「好評」和「差評」,Ajax技術咱們在以前的章節中已經介紹過了,此處再也不贅述。
首先修改項目的urls.py文件,爲「好評」和「差評」功能映射對應的URL。
from django.contrib import admin from django.urls import path from vote import views urlpatterns = [ path('', views.show_subjects), path('teachers/', views.show_teachers), path('praise/', views.prise_or_criticize), path('criticize/', views.prise_or_criticize), path('admin/', admin.site.urls), ]
設計視圖函數praise_or_criticize
來支持「好評」和「差評」功能,該視圖函數經過Django封裝的JsonResponse類將字典序列化成JSON字符串做爲返回給瀏覽器的響應內容。
def praise_or_criticize(request): """好評""" try: tno = int(request.GET['tno']) teacher = Teacher.objects.get(no=tno) if request.path.startswith('/prise'): teacher.good_count += 1 else: teacher.bad_count += 1 teacher.save() data = {'code': 200, 'hint': '操做成功'} except (KeyError, ValueError, Teacher.DoseNotExist): data = {'code': 404, 'hint': '操做失敗'} return JsonResponse(data)
修改顯示老師信息的模板頁,引入jQuery庫來實現事件處理、Ajax請求和DOM操做。
<script src="{% static 'js/jquery.min.js' %}"></script> <script> $(() => { $('.comment>a').on('click', (evt) => { evt.preventDefault(); let a = $(evt.target) let span = a.next() $.getJSON(a.attr('href'), (json) => { if (json.code == 200) { span.text(parseInt(span.text()) + 1) } else { alert(json.hint) } }) }) }) </script>
到此爲止,這個投票項目的核心功能已然完成,在下面的章節中咱們會要求用戶必須登陸才能投票,沒有帳號的用戶能夠經過註冊功能註冊一個帳號。