Python的100天打卡(上)

首先附上Python的官方中文文檔
在刷微信中看到了一個百天打卡學習Python的項目斥铺,就參加了彻桃,下面是筆記。

5.8

1.歷史
2.優(yōu)缺點
3.應用領域
4.三大平臺安裝Python
5.編寫hello,word并運行
6.介紹注釋
7.IDE及插件
8.作業(yè):


順便運行了下小豬佩奇的代碼晾蜘,畫的不錯


5.9

1.“馮·諾依曼結構”
2.數(shù)據(jù)類型
3.變量命名規(guī)則
4.運算符
5.作業(yè):
練習1:華氏溫度轉攝氏溫度

f = input('請輸入華氏溫度:')
try:
    f = float(f)
except:
    print('請輸入正確的華氏溫度')
else:
    c = 5 * (f - 32) / 9
    print('華氏溫度 %.2f = %.2f 攝氏度' % (f,c))

練習2:輸入圓的半徑計算計算周長和面積

import math
r = input('請輸入圓的半徑:')
try:
    r = float(r)
except:
    print('請輸入正確的半徑')
else:
    c = 2 * math.pi * r
    s = math.pi * r * r
    print('圓的周長為:%.2f,面積為:%.2f' % (c,s))

練習3:輸入年份判斷是不是閏年

year = input('請輸入年份:')
try:
    year = int(year)
except:
    print('請輸入正確的年份')
else:
    if (year > 0 and year < 9999):
        if((year % 4 == 0) and (year % 100 != 0)):
            print('%d是閏年' % year)
        elif year % 400 == 0:
            print('%d是閏年' % year)
        else:
            print('%d是平年' % year)
    else:
        print('請輸入正確的年份')

5.10

1.if判斷
2.作業(yè):
練習1:英制單位與公制單位互換

value = input('請輸入長度:')
try:
    value = float(value)
except:
    print('請輸入正確的長度')
else:
    unit = input('請輸入單位: ')
    if unit == 'in' or unit == '英寸':
        print('%.2f英寸 = %.2f厘米' % (value, value * 2.54))
    elif unit == 'cm' or unit == '厘米':
        print('%.2f厘米 = %.2f英寸' % (value, value / 2.54))
    else:
        print('請輸入正確的單位')

練習2:擲骰子決定做什么

from random import randint
def dosth(var):
    return {
        1 : '好',
        2 : '很好',
        3 : '真好',
        4 : '太好',
        5 : '非常好',
        6 : '666'
    }.get(var,'error')
shaizi = randint(1, 6)
print(dosth(shaizi))

練習3:百分制成績轉等級制

s = input('請輸入成績: ')
try:
    s = float(s)
except:
    print('請輸入正確的成績')
else:
    if s >= 90:
        g = 'A'
    elif s >= 80:
        g = 'B'
    elif s >= 70:
        g = 'C'
    elif s >= 60:
        g = 'D'
    else:
        g = 'E'
    print('%.2f對應的等級: %c' % (s,g))

練習4:輸入三條邊長如果能構成三角形就計算周長和面積

import math
a = input('請輸入整數(shù)邊長a: ')
b = input('請輸入整數(shù)邊長b: ')
c = input('請輸入整數(shù)邊長c: ')
try:
    a = int(a)
    b = int(b)
    c = int(c)
except:
    print('請輸入正確的邊長a,b,c')
else:
    if a + b > c and b + c > a and a + c > b:
        perimeter = a+b+c
        area = math.sqrt((a + b + c) * (a + b - c) * (a + c - b) * (b + c - a)) / 4
        print('周長為:%d, 面積為:%.2f' % (perimeter, area))
    else:
        print('輸入的三邊不能構成三角形')

練習5:個人所得稅計算器

新稅法看了發(fā)現(xiàn)好麻煩邻眷,各種扣除累計的,不寫了

5.11

1.for-in循環(huán)
2.while循環(huán)
3.作業(yè):
練習1:輸入一個數(shù)判斷是不是素數(shù)

import math
n = input('請輸入一個整數(shù): ')
try:
    n = int(n)
except:
    print('請輸入正確的數(shù)')
else:
    isP = n > 1
    m = int(math.sqrt(n))
    for i in range(2, m+1):
        if n % i == 0:
            isP = False
            break
    if isP: print('%d 是素數(shù)' % n)
    else  : print('%d 不是素數(shù)' % n)

練習2:輸入兩個正整數(shù)剔交,計算最大公約數(shù)和最小公倍數(shù)

# " / "就表示 浮點數(shù)除法肆饶,返回浮點結果;" // "表示整數(shù)除法(向下取整)
m = input('請輸入一個整數(shù)m: ')
n = input('請輸入一個整數(shù)n: ')
try:
    m = int(m)
    n = int(n)
except:
    print('請輸入正確的數(shù)')
else:
    if m < n:
        m, n = n, m
    for i in range(m, m-n, -1):
        if m % i == 0 and n % i == 0:
            print('%d和%d的最大公約數(shù)是:%d,最小公倍數(shù)是:%d' % (m, n, i, (m * n // i)))
            break

練習3:打印三角形圖案

# 變量_表示并不使用此變量,只是為了閱讀省容,忽略即可
# 參數(shù)end代表結尾字符抖拴,默認是換行/n
r = input('請輸入行數(shù)r: ')
try:
    r = int(r)
except:
    print('請輸入正確的行數(shù)')
else:
    if r < 1:
        print('請輸入正確的行數(shù)')
    else:
        for i in range(r):
            for _ in range(r - i - 1):
                print(' ', end='')
            for _ in range(2 * i + 1):
                print('*', end='')
            print()

5.12

今日主要是復習和總結,只有5個練習。
1.尋找“水仙花數(shù)”

# 最簡單直接的暴搜阿宅,我就不優(yōu)化了
for x in range(1, 10):
    for y in range(0, 10):
        for z in range(0, 10):
            i = x * 100
            j = y * 10
            l = x * x * x
            m = y * y * y
            n = z * z * z
            if i+j+z == l+m+n:
                print(i+j+z)

2.尋找“完美數(shù)”

# 我只找1000內(nèi)的完美數(shù)候衍,同樣的暴搜
for x in range(1, 1001):
    sum = 0
    for i in range(1, x):
        if x % i == 0:
            sum += I
    if(sum == x):print(x)

3.“百錢百雞”

# 繼續(xù)暴搜,簡單無腦
x = 5
y = 3
z = 1 / 3
for i in range(0, 100 // x):
    for j in range(0, 100 // y):
        if (x * i + y * j + z * (100 - i - j) == 100):
            print('公雞%d只洒放,母雞%d只蛉鹿,小雞%d只' % (i,j,100-i-j))

4.生成“斐波拉切數(shù)列”

# 就列100個吧
r = [1,1]
while len(r) < 100:
    r.append(r[-1] + r[-2])
print(r)

5.Craps賭博游戲

# 只要繼續(xù)賭,就沒有所謂的贏
from random import randint
money = 1000
while money > 0:
    print('你的總資產(chǎn)為:', money)
    needs_go_on = False
    while True:
        debt = int(input('請下注: '))
        if debt > 0 and debt <= money:
            break
        else:print('您下注的金額不正確往湿,請重新下注')
    first = randint(1, 6) + randint(1, 6)
    print('玩家搖出了%d點' % first)
    if first == 7 or first == 11:
        print('玩家勝!')
        money += debt
    elif first == 2 or first == 3 or first == 12:
        print('莊家勝!')
        money -= debt
    else:
        needs_go_on = True
    while needs_go_on:
        current = randint(1, 6) + randint(1, 6)
        print('玩家搖出了%d點' % current)
        if current == 7:
            print('莊家勝')
            money -= debt
            needs_go_on = False
        elif current == first:
            print('玩家勝')
            money += debt
            needs_go_on = False
print('You are bankrupt and the game is over!')

5.13

1.認識函數(shù)
2.函數(shù)的定義def
3.函數(shù)的參數(shù)
4.用模塊管理函數(shù)
4.1 from 文件名 import 函數(shù)名
4.2 import 文件名 as 變量名
4.3 防止誤運行妖异,文件中加 if __name__ == '__main__':
5.練習:
練習1:實現(xiàn)計算求最大公約數(shù)和最小公倍數(shù)的函數(shù)

def gys(m, n):
    if m < n:
        m, n = n, m
    for i in range(m, m-n, -1):
        if m % i == 0 and n % i == 0:
            print('%d和%d的最大公約數(shù)是:%d,最小公倍數(shù)是:%d' % (m, n, i, (m * n // i)))
            
if __name__ == '__main__':
    m = input('請輸入一個整數(shù)m: ')
    n = input('請輸入一個整數(shù)n: ')
    try:
        m = int(m)
        n = int(n)
    except:
        print('請輸入正確的數(shù)')
    else:
        gys(m, n)

練習2:實現(xiàn)判斷一個數(shù)是不是回文數(shù)的函數(shù)

def hws(n):
    return n == n[::-1]

if __name__ == '__main__':
    n = input('請輸入一個數(shù)n: ')
    try:
        int(n)
    except:
        print('請輸入正確的數(shù)')
    else:
        print(n, '是回文數(shù):', hws(n))

練習3:實現(xiàn)判斷一個數(shù)是不是素數(shù)的函數(shù)

import math
def sushu(n):
    isP = n > 1
    m = int(math.sqrt(n))
    for i in range(2, m+1):
        if n % i == 0:
            isP = False
            break
    return isP

if __name__ == '__main__':
    n = input('請輸入一個整數(shù): ')
    try:
        n = int(n)
    except:
        print('請輸入正確的數(shù)')
    else:
        print(n, '是素數(shù):', sushu(n))

練習4:寫一個程序判斷輸入的正整數(shù)是不是回文素數(shù)

import math
def hws(n):
    return n == n[::-1]

def sushu(n):
    isP = n > 1
    m = int(math.sqrt(n))
    for i in range(2, m+1):
        if n % i == 0:
            isP = False
            break
    return isP

def hwss(n):
    if hws(n):
        return sushu(m)
    else:
        return False

if __name__ == '__main__':
    n = input('請輸入一個整數(shù): ')
    try:
        m = int(n)
    except:
        print('請輸入正確的數(shù)')
    else:
        print(n, '是回文素數(shù):', hwss(n))

6.變量作用域(局部”->“嵌套nonlocal”->“全局global”->“內(nèi)置”)
7.代碼書寫:

def main():
    # Todo: Add your code here
    pass


if __name__ == '__main__':
    main()

5.14

1.字符串
2.列表
3.元組
4.集合
5.字典
6.練習
練習1:在屏幕上顯示跑馬燈文字

import os
import time
def main():
    content = '這是一條跑馬燈廣告…………'
    while True:
        os.system('clear')  # windows用cls
        print(content)
        time.sleep(0.2)
        content = content[1:] + content[0]


if __name__ == '__main__':
    main()

練習2:設計一個函數(shù)產(chǎn)生指定長度的驗證碼,驗證碼由大小寫字母和數(shù)字構成

import random
def creatCode(n = 6):
    all = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    code = ''
    while len(code) < n:
        i = random.randint(0, len(all) - 1)
        code += all[I]
    return code

if __name__ == '__main__':
    print(creatCode())

練習3:設計一個函數(shù)返回給定文件名的后綴名

def findName(fileName):
    return fileName.split('.')[-1]

if __name__ == '__main__':
    print(findName('abc.mp3'))

練習4:設計一個函數(shù)返回傳入的列表中最大和第二大的元素的值

def towMax(numlist):
    numlist.sort()
    return numlist[-1], numlist[-2]

if __name__ == '__main__':
    print(towMax([1,9,7,45,8,4,8,15,2,5]))

練習5:計算指定的年月日是這一年的第幾天

# 就不對年月日做限制了
def yearToDay():
    year  = input('請輸入年:')
    month = input('請輸入月:')
    day   = input('請輸入天:')
    try:
        year = int(year)
        month = int(month)
        day = int(day)
    except:
        print('請輸入正確年月日')
    days = [31,28,31,30,31,30,31,31,30,31,30,31]
    sum = day
    i = 0
    if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
        days[1] = 29
    while i < month-1:
        sum += days[I]
        i += 1
    print('這是該年的第',sum,'天')

if __name__ == '__main__':
    yearToDay()

練習6:打印楊輝三角

def yanghui():
    num = input('請輸入行數(shù):')
    try:
        num = int(num)
    except:
        print('請輸入正確的行數(shù)')
    else:
        yh = [[]] * num
        for row in range(len(yh)):
            yh[row] = [0] * (row + 1)
            for col in range(len(yh[row])):
                if col == 0 or col == row:
                    yh[row][col] = 1
                else:
                    yh[row][col] = yh[row - 1][col] + yh[row - 1][col - 1]
                print(yh[row][col], end='\t')
            print()

if __name__ == '__main__':
    yanghui()

7.案例
案例1:雙色球選號(sample函數(shù))
案例2:約瑟夫環(huán)問題
案例3:井字棋游戲


5.15

1.面向對象編程的歷史原因
2.定義類
2.1 class
2.2 def __init__(self, *args):
2.3 寫在類中的函數(shù)领追,我們通常稱之為(對象的)方法他膳,這些方法就是對象可以接收的消息
3.創(chuàng)建和使用對象
4.private(__ + 屬性名或方法名),public
5.封裝
6.練習
練習1:定義一個類描述數(shù)字時鐘

import time
class Clock(object):
    '''時間'''
    def __init__(self, h=0, m=0, s=0):
        '''初始化'''
        self.h = h
        self.m = m
        self.s = s
    def cal(self):
        '''計算時間'''
        self.s += 1
        if self.s == 60:
            self.s = 0
            self.m += 1
            if self.m == 60:
                self.m = 0
                self.h += 1
                if self.h == 24:
                    self.h = 0
    def __str__(self):
        '''顯示時間'''
        return '%02d:%02d:%02d' % \
               (self.h, self.m, self.s)

if __name__ == '__main__':
    c = Clock(time.localtime().tm_hour, time.localtime().tm_min, time.localtime().tm_sec)
    while True:
        print(c)
        time.sleep(1)
        c.cal()

練習2:定義一個類描述平面上的點并提供移動點和計算到另一個點距離的方法

# 本來還加了個abs绒窑,后面反應過來平方了就不需要abs了
import math
class Point(object):
    '''時間'''
    def __init__(self, x=0, y=0):
        '''初始化'''
        self.x = x
        self.y = y
    def moveTo(self, x, y):
        self.x = x
        self.y = y
    def distance(self, p):
        '''計算距離'''
        a = p.x - self.x
        b = p.y - self.y
        return math.sqrt(a ** 2 + b ** 2)
    def __str__(self):
        '''描述自己'''
        return '(%s, %s)' % (str(self.x), str(self.y))

if __name__ == '__main__':
    p1 = Point(1,2)
    p2 = Point(3,5)
    print(p1,'\n',p2)
    p1.moveTo(10,6)
    print(p1)
    print(p1.distance(p2))

5.16

1.@property裝飾器(getter)
2.@屬性名.setter
3.綁定__slots__不繼承
4.@staticmethod靜態(tài)方法(參數(shù)無self)
5.@classmethod類方法(參數(shù)cls)
6.類的關系:is-a繼承棕孙,has-a關聯(lián)(聚合,合成)些膨,use-a依賴
7.繼承:子類重寫(override)父類(可用于抽象類)方法后蟀俊,出現(xiàn)多態(tài)
8.@abstractmethod抽象方法,子類必須重寫
9.三個案例订雾,竟然沒有練習肢预,輕松一天,哈哈洼哎。烫映。。

這張UML的圖挺好:

5.17

今天的主要課程是GUI,由于以前接觸過谱净,用過PyQt等窑邦,發(fā)現(xiàn)Python的GUI雖然是跨平臺,但體驗很差壕探,效率很低冈钦,個人認為目前用Python做GUI開發(fā)并不理想,所以今天的課程只做了解李请。
1.tkinter
2.Pygame開發(fā)游戲
3.Pygame的官方網(wǎng)站


5.18

1.文件操作(r默認讀,w寫,x不覆蓋的寫,a追加,b二進制,t文本模式,+重置更新)
2.open(路徑瞧筛,權限,編碼)
3.open錯誤類型(FileNotFoundError,LookupError,UnicodeDecodeError)
4.finally關閉文件釋放資源---“總是執(zhí)行代碼塊”(try-except-else-finally)
5.讀(read,for-in,readlines)
6.寫(w,a追加式寫入)
7.json模塊(dump-load文件导盅,dumps-loads字符串)
8.requests模塊
9.《總結:Python中的異常處理》


5.19

今日課程主要是講正則较幌,用的時候再學吧,以前學過白翻,不用就忘記了乍炉。绢片。
《正則表達式30分鐘入門教程》


5.20

1.進程和線程,幾核CPU幾個進程岛琼,一個進程內(nèi)可有多個線程
2.并發(fā)編程:多進程底循、多線程、多進程+多線程
3.os.getpid()獲取當前進程的PID,os.getppid()獲取父進程的PID
4.注意zombie
5.os.fork()槐瑞,fork函數(shù)一旦運行就會生出一條新的進程熙涤,2個進程一起執(zhí)行,有2個返回值困檩,返回值為大于0時祠挫,此進程為父進程,且返回的數(shù)字為子進程的PID悼沿;當返回值為0時等舔,此進程為子進程。父進程結束時显沈,子進程并不會隨父進程立刻結束软瞎。同樣逢唤,父進程不會等待子進程執(zhí)行完
6.Process對象的start方法用來啟動進程拉讯,而join方法表示等待進程執(zhí)行結束。Process的參數(shù)一定要加,,當時看的時候以為作者筆誤多了個,鳖藕,后來發(fā)現(xiàn)不加的話魔慷,傳進去的字符串每個字節(jié)都成了一個參數(shù)。著恩。院尔。
6.每個進程會復制父類的變量,解決:Queue類是可以被多個進程共享的隊列
7.線程Thread
8.需要對“臨界資源”加鎖Lock()-acquire()-release()
9.Python的多線程并不能發(fā)揮CPU的多核特性“全局解釋器鎖”(GIL)
10.單進程單線程+異步I/O執(zhí)行多任務(Ngix,Node.js),此編程模型稱為協(xié)程,優(yōu)勢:不用線程切換喉誊、不用鎖
11.案例:
1.將耗時間的任務放到線程中以獲得更好的用戶體驗
2.使用多進程對復雜任務進行“分而治之”
12.可以將多個進程部署在不同的計算機上邀摆,做成分布式進程:通過multiprocessing.managers模塊中提供的管理器將Queue對象通過網(wǎng)絡共享出來(注冊到網(wǎng)絡上讓其他計算機可以訪問)


5.21

  1. 計算機網(wǎng)絡發(fā)展史
  2. TCP/IP模型(自下向上:網(wǎng)絡接口層、網(wǎng)絡層伍茄、傳輸層栋盹、應用層,TCP:傳輸控制協(xié)議敷矫,功能:基于IP提供的尋址和路由服務而建立起來的負責實現(xiàn)端到端可靠傳輸?shù)膮f(xié)議例获。IP:網(wǎng)際協(xié)議,功能:尋址和路由)
  3. 網(wǎng)絡應用模式(C/S模式曹仗,B/S模式榨汤。C為客戶端,B為瀏覽器怎茫,S為服務器)
  4. HTTP超文本傳輸協(xié)議收壕,是一種用于分布式、協(xié)作式和超媒體信息系統(tǒng)的應用層協(xié)議。
  5. JSON是一種輕量級的數(shù)據(jù)交換語言蜜宪,用來傳輸由屬性值或者序列性的值組成的數(shù)據(jù)對象旬渠。
  6. requests是一個基于HTTP協(xié)議來使用網(wǎng)絡的第三方庫。
  7. socket套接字(TCP和UDP)
  8. SMTP(簡單郵件傳輸協(xié)議),建立在TCP提供的可靠數(shù)據(jù)傳輸服務的基礎上的應用級協(xié)議端壳。
  9. 使用互億無線短信平臺發(fā)送短信

5.22

  1. 圖像(RGBA,pixel)
  2. Pillow可以實現(xiàn)圖像壓縮和圖像處理等各種操作告丢。
  3. openpyxl讀取和讀取和修改Excel
  4. python-docx創(chuàng)建和修改Word文檔
  5. 下面把例子整理成了一個類
from PIL import Image, ImageFilter

class GCImage(object):
    def __init__(self, path):
        self.path = path
        self.image = Image.open(self.path)
    def show(self):
        print(self.image.format, self.image.size, self.image.mode)
        self.image.show()
    def crop(self, rect):
        '''剪裁'''
        self.image.crop(rect).show()
    def thumb(self, size):
        '''縮略圖'''
        self.image.thumbnail(size)
        self.show()
    def paste(self, img, rect, size):
        '''粘貼'''
        nImg = img.crop(rect)
        width, height = nImg.size
        width, height = int(width / 1.5), int(height / 1.5)
        self.image.paste(nImg.resize((width ,height)), size)
        self.show()
    def roAndTr(self, angle, direction):
        '''旋轉和翻轉'''
        self.image.rotate(angle).show()     #作者github中寫成了image.rotata(180).show()
        self.image.transpose(direction).show()
    def makePixel(self, xRange, yRange, RGB):
        '''操作像素'''
        for x in xRange:
            for y in yRange:
                self.image.putpixel((x, y), rgb)
        self.image.show()
    def filter(self, mode):
        '''濾鏡'''
        self.image.filter(mode).show()

if __name__ == '__main__':
    path1 = '.\\guido.jpg'
    img1 = GCImage(path1)
    # img1.show()

    # img1.crop((20,20,300,300))

    # img1.thumb((50,50))

    # path2 = '.\\luohao.png'
    # img2 = GCImage(path2)
    # rect = 80, 20, 310, 360
    # size = 172, 40
    # img2.paste(img1.image, rect, size)

    # img1.roAndTr(180, Image.FLIP_LEFT_RIGHT)

    # xRange = range(80,310)
    # yRange = range(20,360)
    # rgb = (66,66,66)
    # img1.makePixel(xRange, yRange, rgb)

    img1.filter(ImageFilter.CONTOUR)

5.23

數(shù)據(jù)結構和算法
1.漸近時間復雜度

  • O(c)常量時間復雜度-布隆過濾器/哈希存儲
  • O(log2n)對數(shù)時間復雜度-折半查找(二分查找)
  • O(n)線性時間復雜度-順序查找/桶排序
  • O(nlog2n)對數(shù)線性時間復雜度-高級排序算法(歸并排序、快速排序)
  • O(n^2)平方時間復雜度-簡單排序算法(選擇损谦、插入岖免、冒泡)
  • O(n^3)立方時間復雜度-Floyd算法/矩陣乘法運算
  • O(2^n)幾何級數(shù)時間復雜度-漢諾塔
  • O(n!)階乘時間復雜度-旅行經(jīng)銷商問題NP

2.漸近空間復雜度
3.排序算法-簡單排序-攪拌排序-順序查找-折半查找
4.使用生成式(推導式)語法
5.嵌套的列表
6.heapq、itertools
7.collections模塊
8.常用算法

  • 窮舉法-暴力破解照捡,一個一個試直到找到正確答案(百人百雞颅湘,五人分魚)
  • 貪婪法-不求最優(yōu),找到當前看來是最好的解法(有限的容器裝無限的東西)
  • 分治法-把問題分解成相同或相似的子問題栗精,不斷分解闯参,直到可以直接求解的程度,最后把子問題的解進行合并得到原問題的解(快速排序)
  • 回溯法-試探法悲立,按選優(yōu)條件向前搜索鹿寨,當搜索到某一步發(fā)現(xiàn)原先選擇不優(yōu)或達不到目標,就退回到上一步重新選擇(騎士巡邏)
  • 動態(tài)規(guī)劃-將問題分解成子問題薪夕,求解并保存子問題的解脚草,避免產(chǎn)生大量的重復運算(以前寫過很多了)

5.24

函數(shù)的使用方式
1.高階函數(shù)(filter,map)

# filter用法(判斷是否是素數(shù),第一個參數(shù)為方法名原献,第二個參數(shù)為傳入方法的參數(shù))
# filter是通過生成 True 和 False 組成的迭代器將可迭代對象中不符合條件的元素過濾掉馏慨;而map返回的則是 True 和 False 組成的迭代器。
import math

def isPrime(n):
    isP = n > 1
    m = int(math.sqrt(n))
    for i in range(2, m+1):
        if n % i == 0:
            isP = False
            break
    return isP

if __name__ == '__main__':
    resultF = filter(isPrime, range(1,10))
    resultM = map(isPrime,range(1,10))
    print(list(resultF))
    print(list(resultM))

2.匿名函數(shù)和內(nèi)聯(lián)函數(shù)(lambda)
3.搜索變量順序(Local->Embedded->Global->Built-in),關鍵字:global,nonlocal(聲明使用嵌套作用域的變量,嵌套作用域內(nèi)必須有該變量,否則報錯)
4.裝飾器函數(shù)(@wraps,記得VNPY就是用這個進行日志的記錄;通過func.__wrapped__方式獲得被裝飾前的函數(shù)或類糙箍,來取消裝飾器的作用)


5.25

面向對象相關知識
1.繼承
2.封裝
3.多態(tài)
4.類與類的關系:is-a(繼承),has-a(關聯(lián)/聚合/合成)慕趴,use-a(依賴)
5.對象的復制(深復制/深拷貝/深度克隆和淺復制/淺拷貝/影子克隆)
6.垃圾回收、循環(huán)引用和弱引用(iOS中的ARC叮盘、MRC)
7.元編程和元類
8.面向對象設計原則

  • 單一職責原則(類的設計要高內(nèi)聚)
  • 開閉原則(軟件實體應該對擴展開發(fā)對修改關閉)
  • 依賴倒轉原則(已被弱化)
  • 里氏替換原則(任何時候可以用子類對象替換掉父類對象)
  • 接口隔離原則(Python中沒有接口的概念)
  • 合成聚合復用原則(優(yōu)先使用強關聯(lián)關系而不是繼承關系復用代碼)
  • 最少知識原則(不要給沒有必然聯(lián)系的對象發(fā)消息)

9.設計模式

  • 創(chuàng)建型模式:單例/工廠/創(chuàng)建者/原型
  • 結構型模式:適配器/門面(外觀)/代理
  • 行為型模式:迭代器/觀察者/狀態(tài)/策略

5.26

迭代器和生成器
1.生成器yield

  • 使用了 yield 的函數(shù)被稱為生成器(generator)秩贰,也是一種迭代器
  • 每次遇到 yield 時函數(shù)會暫停并保存當前所有的運行信息,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時從當前位置繼續(xù)運行
  • 創(chuàng)建:generator_eg = (i*i for i in range(10))

2.迭代器__iter____next__

  • iter創(chuàng)建迭代器
  • next從迭代器中取出下一個元素

3.當沒有下一個元素的時候會拋出StopIteration錯誤
4.可迭代對象Iterable:
4.1 list,tuple,dict,set,str等集合數(shù)據(jù)類型
4.2 generator柔吼,包括生成器和帶yield的generator function
4.3 集合數(shù)據(jù)類型用iter創(chuàng)建成Iterator
5.使用isinstance()判斷一個對象是否為可Iterable對象

from collections import Iterable
isinstance([], Iterable)

def fib(n):
    i, a, b = 0, 0, 1
    while i < n:
        yield b
        a, b = b, a+b
        i += 1

if __name__ == '__main__':
    a = fib(10)
    try:
        x = a.__next__()
        while x:
            print(x)
            x = a.__next__()
    except StopIteration:
        print('輸出完成')

5.27

并發(fā)編程
1.并發(fā)編程的三種方案:多線程(Thread類)毒费、多進程(Process類)和異步I/O。
2.進程和線程的區(qū)別和聯(lián)系:進程-操作系統(tǒng)分配內(nèi)存的基本單位(一個進程可以包含一個或多個線程)愈魏;線程-操作系統(tǒng)分配CPU的基本單位
3.并發(fā)編程優(yōu)點:1)執(zhí)行性能-讓程序中沒有因果關系的部分可以并發(fā)的執(zhí)行;2)改善用戶體驗-讓耗時間的操作不會造成程序的假死
4.臨界資源就是被多個線程競爭的資源
5.鎖(Lock/RLock)-保護臨界資源觅玻,解決多個線程競爭一個資源的問題
6.信號量(Semaphore)-解決多個線程競爭多個資源(線程數(shù)>資源數(shù))
7.threading模塊的Condition實現(xiàn)線程調(diào)度(暫停線程執(zhí)行/喚醒等待中的線程)
8.多線程場景:

  • 程序需要維護許多共享的狀態(tài)(尤其是可變狀態(tài))想际,Python中的列表、字典溪厘、集合都是線程安全的胡本,所以使用線程而不是進程維護共享狀態(tài)的代價相對較小。
  • 程序會花費大量時間在I/O操作上畸悬,沒有太多并行計算的需求且不需占用太多的內(nèi)存侧甫。

9.多進程場景:

  • 程序執(zhí)行計算密集型任務(如:字節(jié)碼操作、數(shù)據(jù)處理蹋宦、科學計算)
  • 程序的輸入可以并行的分成塊披粟,并且可以將運算結果合并。
  • 程序在內(nèi)存使用方面沒有任何限制且不強依賴于I/O操作(如:讀寫文件冷冗、套接字等)

10.通過asyncio模塊和awaitasync關鍵字來支持異步處理

import asyncio
loop = asyncio.get_event_loop()
future = asyncio.gather(prime_filter(2, 100), square_mapper(1, 100))
future.add_done_callback(lambda x: print(x.result()))
loop.run_until_complete(future)
loop.close()

get_event_loop獲取系統(tǒng)默認的事件循環(huán)守屉,通過gather函數(shù)獲取future對象
11.aiohttp庫提供了異步的HTTP客戶端和服務器
12.還有很多第三方庫,需要用的時候再google吧蒿辙。拇泛。。


5.28-6.7(本來是十天的內(nèi)容思灌,但中間耽誤了一天)

1.書:HTML and CSS: Design and Build Websites
2.HTML簡史
3.H5新特性
4.標簽:
4.1結構

+ head
    - title
    - meta
+ body

4.2常用標簽

  • 標題和段落h1-h6,p
  • 上標和下標sup,sub
  • 換行br無結束俺叭,分格線hr無結束
  • 加粗strong
  • 縮寫abbr,另一個不支持h5,就不寫了
  • 引文斜體cite
  • 所有者信息address
  • 下劃線ins习瑰,刪除線del
  • 列表:有序(ol-li)绪颖,無序(ul-li),定義(dl-一級dt-二級dd)
  • 鏈接Anchor對象,常用屬性href甜奄、name、target等
  • 圖片image
  • 圖文figure-figcaption
  • 表格table-tr-td窃款,caption,rowspan/colspan,thead/tbody/tfoot
  • 表單form课兄,action/method
  • 音視頻audio/video

5.css
6.JavaScript
6.1 BOM瀏覽器對象模型
6.2 DOM文檔對象模型

  • 訪問元素
  • 操作元素
  • 事件處理

7.jQuery
8.Ajax
9.前端框架
9.1 漸進式框架Vue.js(話說只要不用學完就忘,去年學這個學了一段時間晨继,能做簡單的事情烟阐,現(xiàn)在已經(jīng)忘完了。)
9.2 UI框架Element
9.3 報表框架-ECharts
9.4 基于彈性盒子的CSS框架Bulma
9.5 響應式布局框架Bootstrap


6.8-6.12 Linux

1.操作系統(tǒng)發(fā)展史(紙帶->批處理系統(tǒng)->分時和實時系統(tǒng)->通用操作系統(tǒng))
2.Linux概述
3.Linux優(yōu)點
4.基礎命令(命令名稱 [參數(shù)] [對象])

  • 獲取登錄信息w/who/last
  • 查看自己使用的Shell ps
  • 查看命令說明whatis
  • 查看命令的位置which/whereis
  • 查看幫助文檔man/info/apropos
  • 切換用戶su 用戶名
  • 以管理員身份執(zhí)行命令sudo
  • 登入登出logout/exit/adduser/userdel/passwd/ssh
  • 查看系統(tǒng)和主機名uname/hostname
  • 重啟和關機reboot/init 6/shutdown/init 0
  • 查看歷史命令history

5.文件和文件夾操作

  • 創(chuàng)建/刪除目錄(文件夾)mkdir/rmdir
  • 創(chuàng)建/刪除文件touch/rm(-i 交互式刪除紊扬,每個刪除都會詢問蜒茄;-r 刪除目錄及目錄中的所有文件夾和文件;-f強制刪除餐屎,忽略不存在的文件檀葛,無任何提示)
  • 切換和查看當前目錄cd/pwd
  • 查看目錄內(nèi)容ls(-l 以長格式查看;-a顯示隱藏文件腹缩;-R遇到目錄要遞歸展開屿聋;-d只列目錄空扎;-S按大小排序;-t按時間排序)
  • 查看文件內(nèi)容cat/head/tail/more/less
  • 拷貝/移動文件cp/mv
  • 查找文件和查找內(nèi)容find/grep(可用正則)
  • 鏈接ln
  • 壓縮/解壓縮/歸檔/解歸檔gzip/gunzip/xz/tar(歸檔是:把多個文件組合到一個文件中润讥。歸檔好處是转锈,把文件數(shù)目變少,有利于降多個文件作為電子郵件附件發(fā)送楚殿,以及備份文件撮慨。壓縮是利用算法將文件有損或無損地處理,以達到保留最多文件信息脆粥,而令文件體積變小甫煞。壓縮好處就是節(jié)約硬盤空間,以及減小電子郵件附件的大小冠绢,提高傳輸效率抚吠。)
  • 其它工具sort(文件內(nèi)容排序)/uniq(檢查刪除重復)/diff(對比文件不同)/tr(替換文件內(nèi)容)/cut(分割截取字節(jié))/paste(合并文件內(nèi)容)/file(查看文件類型/編碼格式)/wc(統(tǒng)計文件信息)

6.管道和重定向

  • 定義:管道是一種通信機制,通常用于進程間的通信(也可通過socket進行網(wǎng)絡通信)弟胀,它表現(xiàn)出來的形式將前面每一個進程的輸出(stdout)直接作為下一個進程的輸入(stdin)楷力,管道命令使用|作為界定符號
  • 查找當前目錄下文件個數(shù)find ./ | wc -l
  • 列出當前路徑下的文件和文件夾,并加編號ls | cat -n
  • 輸出重定向>是定向輸出到文件孵户,如果文件不存在萧朝,就創(chuàng)建文件;如果文件存在夏哭,就將其清空检柬;一般我們備份清理日志文件的時候,就是這種方法:先備份日志竖配,再用>何址,將日志文件清空(文件大小變成0字節(jié))/>>這個是將輸出內(nèi)容追加到目標文件中。如果文件不存在进胯,就創(chuàng)建文件用爪;如果文件存在,則將新的內(nèi)容追加到那個文件的末尾胁镐,該文件中的原有內(nèi)容不受影響/2>是將錯誤輸出
  • 輸入重定向<

7.別名alias/unalias
8.日期和時間date/cal

9.文件系統(tǒng)
9.1 目錄

  • /bin 基本命令的二進制文件
  • /boot 引導加載程序的靜態(tài)文件
  • /dev 設備文件
  • /etc 配置文件
  • /home 普通用戶目錄的父目錄
  • /lib 共享庫文件
  • /lib64 共享64位庫文件
  • /lost+found 存放未鏈接文件
  • /media 自動識別設備的掛載目錄
  • /mnt 臨時掛載文件系統(tǒng)的掛載點
  • /opt 可選插件軟件包安裝位置
  • /proc 內(nèi)核和進程信息
  • /root 超級管理員用戶主目錄
  • /run 存放系統(tǒng)運行時需要的東西
  • /sbin 超級用戶的二進制文件
  • /sys 設備的偽文件系統(tǒng)
  • /tmp 臨時文件夾
  • /usr 用戶應用目錄
  • /var 變量數(shù)據(jù)目錄

9.2 訪問權限(chmod修改權限/chown修改文件所有者)
10.磁盤管理(df查看使用情況/fdisk分區(qū)表操作/mkfs格式化/fsck文件系統(tǒng)檢查/mount掛載/umount卸載)
11.編輯器Vim

  • 啟動vim + 文件名
  • i進入編輯模式
  • w保存q退出
  • -d比較文件

12.軟件安裝和配置
12.1 包管理工具yum(Yellowdog Updater Modified)

  • yum search + 包名 搜索軟件包
  • yum list installed列出安裝的軟件包(yum list installed | grep zlib)
  • yum install + 包名安裝軟件包
  • yum remove + 包名刪除軟件包
  • yum update更新所有軟件包
  • yum check-update檢查有哪些可以更新的軟件包
  • yum info + 包名顯示軟件包的信息

12.2 rpm(Redhat Package Manager)

  • rpm -ivh <包名>.rpm安裝軟件包
  • rpm -e <包名>刪除軟件包
  • rpm -qa | grep +包名查詢是否安裝該軟件

13.配置服務

  • systemctl start firewalld啟動服務
  • systemctl stop firewalld停止服務
  • systemctl restart firewallld重啟服務
  • systemctl status firewalld查看服務
  • systemctl enable firewalld設置開機自啟
  • systemctl disable firewalld關閉開機自啟

14.計劃任務crontab
15.網(wǎng)絡訪問和管理

  • ssh安全遠程連接
  • wget通過網(wǎng)絡獲取資源(b后臺下載模式/O下載到指定的目錄/r遞歸下載)
  • ip顯示/操作網(wǎng)絡配置
  • ping檢查網(wǎng)絡可達性
  • netstat查看網(wǎng)絡服務和端口netstat -nap | grep nginx
  • scp安全文件拷貝
  • sftp安全文件傳輸(help/ls顯示遠端目錄列表/lls顯示本地目錄列表/cd切換遠端路徑/lcd切換本地路徑/mkdir創(chuàng)建遠端目錄/lmkdir創(chuàng)建本地目錄/pwd顯示遠端當前工作目錄/lpwd顯示本地當前工作目錄/get下載文件/put上傳文件/rm刪除遠端文件/bye/exit/quit退出sftp)

16.進程管理

  • ps查看進程ps -ef/ps -ef | grep+進程名
  • kill終止進程
  • ctrl+Z偎血,&將進程置于后臺
  • jobs查詢后臺進程
  • bg讓進程在后臺繼續(xù)運行
  • fg將后臺進程置于前臺
  • ctrl+C結束前臺的進程
  • top進程監(jiān)控

17.系統(tǒng)性能

  • sar查看系統(tǒng)活動信息
  • free查看內(nèi)存使用情況
  • pmap查看進程使用內(nèi)存情況
  • iostat報告設備CPU和I/O統(tǒng)計信息

6.13-6.18(中間又偷懶了一天)

1.NoSQL按存儲類型分為:

  • 列族數(shù)據(jù)庫:按列存儲數(shù)據(jù),最大的特點是方便存儲結構化和半結構化數(shù)據(jù)盯漂,方便做數(shù)據(jù)壓縮颇玷,對針對某一列或者某幾列的查詢有非常大的I/O優(yōu)勢,適合于批量數(shù)據(jù)處理和即時查詢(Hypertable)
  • 文檔數(shù)據(jù)庫:一般存儲JSON數(shù)據(jù)就缆,內(nèi)容是文檔型的帖渠,這樣就有機會對某些字段建立索引,實現(xiàn)關系數(shù)據(jù)庫的某些功能违崇,但不提供對參照完整性和分布事務的支持(MongoDB)
  • KV數(shù)據(jù)庫:通過Key快速查詢到Value阿弃,有基于內(nèi)存和基于磁盤兩種實現(xiàn)方式(Redis)
  • 圖數(shù)據(jù)庫:使用圖結構進行語義查詢的數(shù)據(jù)庫诊霹,它使用節(jié)點、邊和屬性來表示和存儲數(shù)據(jù)渣淳。圖數(shù)據(jù)庫從設計上就可以簡單快速的檢索(難以在關系系統(tǒng)中建模的)復雜層次結構
  • 對象數(shù)據(jù)庫:通過類似面向對象語言的語法操作數(shù)據(jù)庫脾还,通過對象的方式存取數(shù)據(jù)

2.Redis(高速緩存/排行榜/商品秒殺/投票點贊/分布式鎖/消息隊列)

  • 官網(wǎng)下載 stable 版本
  • 解壓:tar zxvf redis-5.0.5.tar
  • 移動到: mv redis-5.0.5 /usr/local/
  • 切換到:cd /usr/local/redis-5.0.5/
  • 編譯測試 sudo make test
  • 編譯安裝 sudo make install
  • 啟動 Redis: redis-server(我就不進行配置了)

2.1 Python中用Redis

import redis

def useRedis():
    client = redis.Redis(host='127.0.0.1', port=6379, password='')
    client.set('username', 'admin')
    client.hset('student', 'name', 'hao')
    client.hset('student', 'age', 38)
    print(client.keys('*'))
    print(client.get('username'))
    print(client.hgetall('student'))

if __name__ == '__main__':
    useRedis()

3.MongoDB
3.1關于安裝及運行在以前的文章已經(jīng)寫過了,這里就不寫了
3.2通過Shell操作MongoDB

  • 連接:mongo --host 127.0.0.1
  • 顯示數(shù)據(jù)庫:show dbs
  • 創(chuàng)建并切換數(shù)據(jù)庫:use +庫名
  • 創(chuàng)建collection:db.createCollection('集合名')
  • 顯示所有collection:show collections
  • 刪除collection:db.集合名.drop()
  • 插入數(shù)據(jù)1:db.students.insert({stuid: 1001, name: 'Steven', age: 38})
  • 插入數(shù)據(jù)2:db.students.save({stuid: 1002, name: '王大錘', tel: '13012345678', gender: '男'})
  • 查看數(shù)據(jù):db.students.find()
  • 更新數(shù)據(jù):db.students.update({stuid: 1001}, {'$set': {tel: '12345678901', gender: '男'}})注意"'
  • 插入更新數(shù)據(jù):db.students.update({stuid: 1003}, {'$set': {name: '白元芳', tel: '13022223333', gender: '男'}}, upsert=true)
  • 查看格式化后的數(shù)據(jù):db.students.find().pretty()
  • 查看stuid大于1001的數(shù)據(jù):db.students.find({stuid: {'$gt': 1001}}).pretty()
  • 查看stuid大于1001的且只顯示name和tel數(shù)據(jù):db.students.find({stuid: {'$gt': 1001}}, {_id: 0, name: 1, tel: 1}).pretty()
  • 查詢name為“steven”或者tel為“13022223333”的數(shù)據(jù):db.students.find({'$or': [{name: 'steven'}, {tel: '13022223333'}]}, {_id: 0, name: 1, tel: 1}).pretty()注意大小寫
  • 查看跳過第1條且只查1看條數(shù)據(jù):db.students.find().skip(1).limit(1).pretty()
  • 查看排序后的數(shù)據(jù)(1表示升序入愧,-1表示降序):db.students.find({}, {_id: 0, stuid: 1, name: 1}).sort({stuid: -1})
  • 根據(jù)指定條件創(chuàng)建索引:db.students.ensureIndex({name: 1})

3.3 在Python中使用Mongo

from pymongo import *

def useMongo():
    client = MongoClient('mongodb://127.0.0.1')
    db = client.school
    for student in db.students.find():
        print('學號:', student['stuid'])
        print('姓名:', student['name'])
    totalNum(db)
    db.students.remove()
    totalNum(db)
    coll = db.students
    coll.create_index([('stuid', ASCENDING)], unique=True)
    coll.insert_one({'stuid': int(1001), 'name': 'Steven', 'gender': True})
    coll.insert_many(
        [{'stuid': int(1002), 'name': '王大錘', 'gender': False}, {'stuid': int(1003), 'name': '白元芳', 'gender': True}])
    for student in coll.find({'gender': True}):
        print('學號:', student['stuid'])
        print('姓名:', student['name'])
        print('性別:', '男' if student['gender'] else '女')

def totalNum(db):
    num = db.students.find().count()
    print('數(shù)量:', num)

if __name__ == '__main__':
    useMongo()

4.關系型數(shù)據(jù)庫(Oracle鄙漏、DB2SQL Server棺蛛、MySQL怔蚌、PostgreSQL)
5.MySQL
5.1關于MySQL的安裝以前也寫過,這里就不寫了旁赊。區(qū)別是現(xiàn)在可以在安裝的時候直接設置密碼了桦踊,這點挺好。
5.2基本命令

  • select version();查看服務器版本
  • show databases;查看所有數(shù)據(jù)庫
  • use mysql;切換到mysql數(shù)據(jù)庫
  • show tables;查看數(shù)據(jù)庫所有的表
  • ? contents;/? functions;/? numeric functions;/? round;/? data types;/? longblob;查看幫助

5.3數(shù)據(jù)定義語言DDL(Data Definition Language)
5.4數(shù)據(jù)操縱語言DML(Data Manipulation Language)
5.5數(shù)據(jù)查詢語言DQL(Data Query Language)
5.6數(shù)據(jù)控制語言DCL(Data Control Language)
5.7相關知識
5.8在Python中使用mysql

import pymysql
from pymysql.cursors import DictCursor

"""
先創(chuàng)建兩張表终畅,數(shù)據(jù)自己填
CREATE TABLE tb_dept (`no` VARCHAR(100) NOT NULL, `name` VARCHAR(100) NOT NULL, `loc` VARCHAR(100) NOT NULL);
CREATE TABLE tb_emp (`no` VARCHAR(100) NOT NULL, `name` VARCHAR(100) NOT NULL, `job` VARCHAR(100) NOT NULL, `sal` VARCHAR(100) NOT NULL );
"""

def addDepartment(con):
    no = int(input('編號: '))
    name = input('名字: ')
    loc = input('所在地: ')
    try:
        # 通過連接對象獲取游標
        with con.cursor() as cursor:
            # 通過游標執(zhí)行SQL并獲得執(zhí)行結果
            result = cursor.execute(
                'insert into tb_dept values (%s, %s, %s)',
                (no, name, loc)
            )
        if result == 1:
            print('添加成功!')
        # 操作成功提交事務
        con.commit()
    finally:
        # 關閉連接釋放資源
        con.close()

def delDepartment(con):
    no = int(input('編號: '))
    try:
        with con.cursor() as cursor:
            result = cursor.execute(
                'delete from tb_dept where no=%s',
                (no,)
            )
        if result == 1:
            print('刪除成功!')
    finally:
        con.close()

def updDepartment(con):
    no = int(input('編號: '))
    name = input('名字: ')
    loc = input('所在地: ')
    try:
        with con.cursor() as cursor:
            result = cursor.execute(
                'update tb_dept set name=%s, loc=%s where no=%s',
                (name, loc, no)
            )
        if result == 1:
            print('更新成功!')
    finally:
        con.close()

def finDepartment(con):
    try:
        with con.cursor(cursor=DictCursor) as cursor:
            cursor.execute('select no as dno, name as dname, loc as dloc from tb_dept')
            results = cursor.fetchall()
            print(results)
            print('編號\t名稱\t\t所在地')
            for dept in results:
                print(dept['dno'], end='\t')
                print(dept['dname'], end='\t')
                print(dept['dloc'])
    finally:
        con.close()

class Emp(object):
    def __init__(self, no, name, job, sal):
        self.no = no
        self.name = name
        self.job = job
        self.sal = sal

    def __str__(self):
        return f'\n編號:{self.no}\n姓名:{self.name}\n職位:{self.job}\n月薪:{self.sal}\n'

def findEmpInfo(con):
    page = int(input('頁碼: '))
    size = int(input('大小: '))
    try:
        with con.cursor() as cursor:
            cursor.execute(
                'select no as eno, name as ename, job, sal from tb_emp limit %s,%s',
                ((page - 1) * size, size)
            )
            for emp_tuple in cursor.fetchall():
                emp = Emp(*emp_tuple)
                print(emp)
    finally:
        con.close()

if __name__ == '__main__':
    # 創(chuàng)建數(shù)據(jù)庫連接對象
    con = pymysql.connect(host='localhost', port=3306,
                          database='mysql', charset='utf8',
                          user='root', password='stevenabc999')
    addDepartment(con)

6.19

1.Web機制和術語
2.HTTP協(xié)議
3.Django概述
3.1 Django安裝conda install django
3.2 靜態(tài)項目

  • 創(chuàng)建:django-admin startproject +項目名 +路徑
  • 項目內(nèi)的文件:
  • manage.py: 一個讓你用各種方式管理 Django 項目的命令行工具籍胯。
  • 項目名/__init__.py:一個空文件,告訴 Python 這個目錄應該被認為是一個 Python 包离福。
  • 項目名/settings.py:Django 項目的配置文件杖狼。
    oa/urls.py:Django 項目的 URL 聲明,就像你網(wǎng)站的“目錄”妖爷。
  • 項目名/wsgi.py:作為你的項目的運行在 WSGI 兼容的Web服務器上的入口蝶涩。
  • cd到項目中,啟動服務器運行項目:python3 manage.py runserver命令后面可以加上IP:PORT
  • 默認127.0.0.1:8000顯示項目
  • 項目名/settings.py修改配置文件(時區(qū)絮识,語言)
 # 設置語言代碼
 LANGUAGE_CODE = 'zh-hans'
 # 設置時區(qū)
 TIME_ZONE = 'Asia/Shanghai'
 USE_TZ = False # 不使用UTC時間(不跨時區(qū))

3.3 創(chuàng)建動態(tài)應用python3 manage.py startapp +應用名

  • 項目文件
  • __init__.py:一個空文件绿聘,告訴 Python 這個目錄應該被認為是一個 Python 包。
  • admin.py:可以用來注冊模型笋除,用于在Django的管理界面管理模型
  • apps.py:當前應用的配置斜友。
  • migrations:存放與模型有關的數(shù)據(jù)庫遷移信息。
  • models.py:存放應用的數(shù)據(jù)模型垃它,即實體類及其之間的關系(MVC/MVT中的M)
  • tests.py:包含測試應用各項功能的測試類和測試函數(shù)。
  • views.py:處理請求并返回響應的函數(shù)(MVC中的C烹看,MVT中的V)国拇。
  • 修改視圖文件views.py
  • 創(chuàng)建urls.py并映射URLtouch 應用名/urls.py
  • 合并項目目錄下的urls.py文件
  • 重新運行項目,并打開127.0.0.1:8000/應用名
  • 修改views.py文件惯殊,刷新即新頁面

3.4 使用視圖模板

  • manage.py文件路徑下創(chuàng)建templates文件:mkdir templates
  • 創(chuàng)建模板頁index.htmltouch templates/index.html
  • 修改templates文件下的index.html酱吝、應用下的views.py、項目下的settings.py
  • 重新運行項目即可python3 manage.py runserver

6.20

1.配置MySQL(ENGINE屬性可用:'django.db.backends.sqlite3'土思、'django.db.backends.postgresql'务热、'django.db.backends.mysql'忆嗜、'django.db.backends.oracle'
2.安裝pymysql(數(shù)據(jù)庫內(nèi)容時我們已經(jīng)安裝過了)
3.修改__init__.py文件,將PyMySQL視為MySQLdb來使用崎岂,從而避免Django找不到連接MySQL的客戶端工具

import pymysql
pymysql.install_as_MySQLdb()

4.數(shù)據(jù)庫遷移捆毫,為應用程序創(chuàng)建對應的數(shù)據(jù)表

# 準備工作:創(chuàng)建表
# drop database if exists +數(shù)據(jù)庫名;
# create database +數(shù)據(jù)庫名 default charset utf8;

合并數(shù)據(jù)表:python3 manage.py migrate
我運行到這里會報錯,說django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.
解決方法是:找到django的mysql下的base.py文件冲甘,我的路徑是/Users/Crazy_Steven/miniconda3/lib/python3.7/site-packages/django/db/backends/mysql/base.py?將以下代碼注釋掉即可

if version < (1, 3, 13):
    raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)

然后又報錯了AttributeError: 'str' object has no attribute 'decode'绩卤,解決辦法很簡單,錯誤上兩行是

File "/Users/Crazy_Steven/miniconda3/lib/python3.7/site-packages/django/db/backends/mysql/operations.py", line 146, in last_executed_query
    query = query.decode(errors='replace')

只要按錯誤內(nèi)容把該路徑下的operations.py文件146行decode改成encode即可江醇,然后繼續(xù)python3 manage.py migrate
5.修改我們需要的數(shù)據(jù)模型vim 應用名/models.py
6.通過模型創(chuàng)建數(shù)據(jù)表python3 manage.py makemigrations 應用名并再次合并python3 manage.py migrate

E-R圖

7.后臺管理系統(tǒng)

  • 創(chuàng)建超級管理員賬號:python3 manage.py createsuperuser按提示輸入用戶名濒憋,郵箱和密碼
  • 啟動Web服務器python manage.py runserver
  • 登錄后臺服務系統(tǒng)http://127.0.0.1:8000/admin
  • 注冊模型類:修改應用名/admin.py文件,通過注冊模型管理類陶夜,可以在后臺管理系統(tǒng)中更好的管理模型
  • 可以在管理員平臺對模型進行C(Create新增)R(Read查看)U(Update更新)D(Delete刪除)操作
  • 可以通過shell進行crud操作:python3 manage.py shell

8.Django模型最佳實踐

  • 正確的為模型和關系字段命名凛驮。
  • 設置適當?shù)?code>related_name屬性。
  • OneToOneField代替ForeignKeyField(unique=True)条辟。
  • 通過“遷移操作”(migrate)來添加模型黔夭。
  • 用NoSQL來應對需要降低范式級別的場景。
  • 如果布爾類型可以為空要使用NullBooleanField捂贿。
  • 在模型中放置業(yè)務邏輯纠修。
  • <ModelName>.DoesNotExists取代ObjectDoesNotExists
  • 在數(shù)據(jù)庫中不要出現(xiàn)無效數(shù)據(jù)厂僧。
  • 不要對QuerySet調(diào)用len()函數(shù)扣草。
  • QuerySetexists()方法的返回值用于if條件。
  • DecimalField來存儲貨幣相關數(shù)據(jù)而不是FloatField颜屠。
  • 定義__str__方法辰妙。
  • 不要將數(shù)據(jù)文件放在同一個目錄中。

9.模型定義參考(此內(nèi)容當作字典甫窟,需要用的時候再來查密浑,記不住)

  • Django模型字段類
字段類 說明
AutoField 自增ID字段
BigIntegerField 64位有符號整數(shù)
BinaryField 存儲二進制數(shù)據(jù)的字段,對應Python的bytes類型
BooleanField 存儲True或False
CharField 長度較小的字符串
DateField 存儲日期粗井,有auto_now和auto_now_add屬性
DateTimeField 存儲日期和日期尔破,兩個附加屬性同上
DecimalField 存儲固定精度小數(shù),有max_digits(有效位數(shù))和decimal_places(小數(shù)點后面)兩個必要的參數(shù)
DurationField 存儲時間跨度
EmailField 與CharField相同浇衬,可以用EmailValidator驗證
FileField 文件上傳字段
FloatField 存儲浮點數(shù)
ImageField 其他同F(xiàn)ileFiled懒构,要驗證上傳的是不是有效圖像
IntegerField 存儲32位有符號整數(shù)。
GenericIPAddressField 存儲IPv4或IPv6地址
NullBooleanField 存儲True耘擂、False或null值
PositiveIntegerField 存儲無符號整數(shù)(只能存儲正數(shù))
SlugField 存儲slug(簡短標注)
SmallIntegerField 存儲16位有符號整數(shù)
TextField 存儲數(shù)據(jù)量較大的文本
TimeField 存儲時間
URLField 存儲URL的CharField
UUIDField 存儲全局唯一標識符
  • 字段屬性
選項 說明
null 數(shù)據(jù)庫中對應的字段是否允許為NULL胆剧,默認為False
blank 后臺模型管理驗證數(shù)據(jù)時,是否允許為NULL醉冤,默認為False
choices 設定字段的選項秩霍,各元組中的第一個值是設置在模型上的值篙悯,第二值是人類可讀的值
db_column 字段對應到數(shù)據(jù)庫表中的列名,未指定時直接使用字段的名稱
db_index 設置為True時將在該字段創(chuàng)建索引
db_tablespace 為有索引的字段設置使用的表空間铃绒,默認為DEFAULT_INDEX_TABLESPACE
default 字段的默認值
editable 字段在后臺模型管理或ModelForm中是否顯示鸽照,默認為True
error_messages 設定字段拋出異常時的默認消息的字典,其中的鍵包括null匿垄、blank移宅、invalid、invalid_choice椿疗、unique和unique_for_date
help_text 表單小組件旁邊顯示的額外的幫助文本漏峰。
primary_key 將字段指定為模型的主鍵,未指定時會自動添加AutoField用于主鍵届榄,只讀浅乔。
unique 設置為True時,表中字段的值必須是唯一的
verbose_name 字段在后臺模型管理顯示的名稱铝条,未指定時使用字段的名稱
  • ForeignKey屬性
  1. limit_choices_to:值是一個Q對象或返回一個Q對象靖苇,用于限制后臺顯示哪些對象。
  2. related_name:用于獲取關聯(lián)對象的關聯(lián)管理器對象(反向查詢)班缰,如果不允許反向贤壁,該屬性應該被設置為'+',或者以'+'結尾埠忘。
  3. to_field:指定關聯(lián)的字段脾拆,默認關聯(lián)對象的主鍵字段。
  4. db_constraint:是否為外鍵創(chuàng)建約束莹妒,默認值為True名船。
  5. on_delete:外鍵關聯(lián)的對象被刪除時對應的動作,可取的值包括django.db.models中定義的:
  • CASCADE:級聯(lián)刪除旨怠。
  • PROTECT:拋出ProtectedError異常渠驼,阻止刪除引用的對象。
  • SET_NULL:把外鍵設置為null鉴腻,當null屬性被設置為True時才能這么做迷扇。
  • SET_DEFAULT:把外鍵設置為默認值,提供了默認值才能這么做爽哎。
  • ManyToManyField屬性
  1. symmetrical:是否建立對稱的多對多關系谋梭。
  2. through:指定維持多對多關系的中間表的Django模型。
  3. throughfields:定義了中間模型時可以指定建立多對多關系的字段倦青。
  4. db_table:指定維持多對多關系的中間表的表名。
  • 模型元數(shù)據(jù)選項
選項 說明
abstract 設置為True時模型是抽象父類
app_label 如果定義模型的應用不在INSTALLED_APPS中可以用該屬性指定
db_table 模型使用的數(shù)據(jù)表名稱
db_tablespace 模型使用的數(shù)據(jù)表空間
default_related_name 關聯(lián)對象回指這個模型時默認使用的名稱盹舞,默認為<model_name>_set
get_latest_by 模型中可排序字段的名稱产镐。
managed 設置為True時隘庄,Django在遷移中創(chuàng)建數(shù)據(jù)表并在執(zhí)行flush管理命令時把表移除
order_with_respect_to 標記對象為可排序的
ordering 對象的默認排序
permissions 創(chuàng)建對象時寫入權限表的額外權限
default_permissions 默認為('add', 'change', 'delete')
unique_together 設定組合在一起時必須獨一無二的字段名
index_together 設定一起建立索引的多個字段名
verbose_name 為對象設定人類可讀的名稱
verbose_name_plural 設定對象的復數(shù)名稱
  • 查詢參考

按字段查找可以用的條件:

  1. exact / iexact:精確匹配/忽略大小寫的精確匹配查詢
  2. contains / icontains / startswith / istartswith / endswith / iendswith:基于like的模糊查詢
  3. in:集合運算
  4. gt / gte / lt / lte:大于/大于等于/小于/小于等于關系運算
  5. range:指定范圍查詢(SQL中的between…and…
  6. year / month / day / week_day / hour / minute / second:查詢時間日期
  7. isnull:查詢空值(True)或非空值(False)
  8. search:基于全文索引的全文檢索
  9. regex / iregex:基于正則表達式的模糊匹配查詢
  • Q對象(用于執(zhí)行復雜查詢)
    eg: 查詢名字以“張”開頭且工資大于等于5000或補貼大于等于1000的員工
from django.db.models import Q
Emp.objects.filter(Q(name__startswith='張'),Q(sal__gte=5000) | Q(comm__gte=1000))

6.21

投票應用,具體的需求是用戶進入應用首先查看到“學科介紹”頁面癣亚,該頁面顯示了一個學校所開設的所有學科丑掺;通過點擊某個學科,可以進入“老師介紹”頁面述雾,該頁面展示了該學科所有老師的詳細情況街州,可以在該頁面上給老師點擊“好評”或“差評”,但是會先跳轉到“登錄頁”要求用戶登錄玻孟,登錄成功才能投票唆缴;對于未注冊的用戶,可以在“登錄頁”點擊“新用戶注冊”進入“注冊頁”完成用戶注冊黍翎,注冊成功后會跳轉到“登錄頁”面徽,注冊失敗會獲得相應的提示信息。

1.cd到項目目錄創(chuàng)建項目:django-admin startproject djangoVote
2.修改配置文件(djangoVote/settings.py)中的語言為中文:LANGUAGE_CODE = 'zh-hans'
3.cd到項目中創(chuàng)建投票應用:python3 manage.py startapp voteApp
4.配置數(shù)據(jù)庫
vim djangoVote/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'voteApp',
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'djangoVote',
        'HOST': 'localhost',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': 'stevenabc999',
    }
}

vim djangoVote/__init__.py

import pymysql
pymysql.install_as_MySQLdb()
drop database if exists djangoVote;
create database djangoVote default charset utf8;

5.合并數(shù)據(jù)庫
python3 manage.py migrate
6.修改數(shù)據(jù)模型vim voteApp/models.py

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='好評數(shù)')
    bad_count = models.IntegerField(default=0, verbose_name='差評數(shù)')
    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 = '老師'

7.“生成遷移”和“執(zhí)行遷移”
python3 manage.py makemigrations voteApp
python3 manage.py migrate
8.使用Django提供的后臺管理應用來添加學科和老師信息(測試數(shù)據(jù))

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)

9.創(chuàng)建使用模版(樣式自己處理)
mkdir templates
touch templates/subject.html
vim templates/subject.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>學科信息</title>
    <style>
        body {
            width: 960px;
            margin: 0 auto;
        }
        .sub {
            margin: 20px 10px;
        }
    </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>

touch templates/teacher.html
vim templates/teacher.html

<!DOCTYPE html>
{% load staticfiles %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>講師信息</title>
    <style>
        body {
            width: 960px;
            margin: 0 auto;
        }
        .sub {
            margin: 20px 10px;
        }
    </style>
</head>
<body>
    <h1>{{ subject.name }}學科老師信息</h1>
    <hr>
    {% if teachers %}
    {% for teacher in teachers %}
    <div class="teacher">
        <div class="photo">
            <img src="{% static teacher.photo %}" height="140" alt="">
        </div>
        <div class="info">
            <h3>{{ teacher.name }}</h3>
            <p>{{ teacher.detail }}</p>
            <p class="comment">
                <a href="/praise/?tno={{ teacher.no }}">好評</a>
                (<span>{{ teacher.good_count }}</span>)
                &nbsp;&nbsp;
                <a href="/criticize/?tno={{ teacher.no }}">差評</a>
                (<span>{{ teacher.bad_count }}</span>)
            </p>
        </div>
    </div>
    {% endfor %}
    {% else %}
    <h3>暫時沒有該學科的老師信息</h3>
    {% endif %}
    <p>
        <a href="/">返回首頁</a>
    </p>
</body>
</html>

vim djangoVote/settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

10.修改views.py文件

def show_subjects(request):
    """查看所有學科"""
    subjects = Subject.objects.all()
    return render(request, 'subject.html', {'subjects': subjects})
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('/')

11.加載靜態(tài)資源
vim djangoVote/settings.py

STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]
STATIC_URL = '/static/'

12.修改urls.py文件,配置用戶請求的URL和視圖函數(shù)的對應關系
vim djangoVote/urls.py

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),
]

13.啟動項目
python3 manage.py runserver
14.修改項目的urls.py文件,為“好評”和“差評”功能映射對應的URL
vim djangoVote/urls.py

    path('praise/', views.praise_or_criticize),
    path('criticize/', views.praise_or_criticize),

15.修改views文件数焊,添加投票
vim voteApp/views.py

def praise_or_criticize(request):
    """好評和差評"""
    try:
        tno = int(request.GET['tno'])
        teacher = Teacher.objects.get(no=tno)
        if request.path.startswith('/praise'):
            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)

16.修改teacher.html模板頁坦康,引入jQuery庫來實現(xiàn)事件處理、Ajax請求和DOM操作

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
    $(() => {
        $('.comment>a').on('click', (evt) => {
            evt.preventDefault()
            let anchor = $(evt.target)
            let url = anchor.attr('href')
            $.getJSON(url, (json) => {
                if (json.code == 10001) {
                    let span = anchor.next()
                    span.text(parseInt(span.text()) + 1)
                } else {
                    alert(json.hint)
                }
            })
        })
    })
</script>

Done.


6.22

實現(xiàn)“用戶注冊”和“用戶登錄”的功能斋配,并限制只有登錄的用戶才能為老師投票

1.添加用戶模型
vim voteApp/models.py

class User(models.Model):
    """用戶"""
    no = models.AutoField(primary_key=True, verbose_name='編號')
    username = models.CharField(max_length=20, unique=True, verbose_name='用戶名')
    password = models.CharField(max_length=32, verbose_name='密碼')
    regdate = models.DateTimeField(auto_now_add=True, verbose_name='注冊時間')

    class Meta:
        db_table = 'tb_user'
        verbose_name_plural = '用戶'

2.合并數(shù)據(jù)庫
python3 manage.py makemigrations voteApp
python3 manage.py migrate
3.添加用戶注冊和登錄模版頁(樣式自己寫)
touch templates/register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶注冊</title>
    <style>
        body {
            width: 960px;
            margin: 0 auto;
        }
        .sub {
            margin: 20px 10px;
        }
    </style>
</head>
<body>
    <h1>用戶注冊</h1>
    <hr>
    <p class="hint">{{ hint }}</p>
    <form action="/register/" method="post">
        {% csrf_token %}
        <div class="input">
            <label for="username">用戶名:</label>
            <input type="text" id="username" name="username">
        </div>
        <div class="input">
            <label for="password">密碼:</label>
            <input type="password" id="password" name="password">
        </div>
        <div class="input">
            <label for="repassword">確認密碼:</label>
            <input type="password" id="repassword" name="repassword">
        </div>
        <div class="input">
            <input type="submit" value="注冊">
            <input type="reset" value="重置">
        </div>
    </form>
    <a href="/login">返回登錄</a>
</body>
</html>

在添加登錄頁前先把驗證碼做好
touch voteApp/authCode.py
vim voteApp/authCode.py

#coding=utf-8
import random
import string
import sys
from io import BytesIO
import math
from PIL import Image,ImageDraw,ImageFont,ImageFilter
 
#字體的位置,不同版本的系統(tǒng)會有不同
font_path = '/Library/Fonts/Arial.ttf'
#生成驗證碼圖片的高度和寬度
size = (200,75)
#背景顏色,默認為白色
bgcolor = (255,255,255)
#干擾線顏色铛嘱。默認為紅色
linecolor = (255,0,0)
#是否要加入干擾線
draw_line = True
#加入干擾線條數(shù)的上下限
line_number = (1,5)

def gene_line(draw,width,height):
    """繪制干擾線"""
    begin = (random.randint(0, width), random.randint(0, height))
    end = (random.randint(0, width), random.randint(0, height))
    draw.line([begin, end], fill = rangem_color())

def rangem_color(start=0, end=255, opacity=255):
    """獲得隨機顏色"""
    red = random.randint(start, end)
    green = random.randint(start, end)
    blue = random.randint(start, end)
    if opacity is None:
        return red, green, blue
    return red, green, blue, opacity
#生成驗證碼
def gene_code(number,text):
    width,height = size #寬和高
    image = Image.new('RGBA',(width,height),bgcolor) #創(chuàng)建圖片
    font = ImageFont.truetype(font_path,40) #驗證碼的字體
    draw = ImageDraw.Draw(image)  #創(chuàng)建畫筆
    font_width, font_height = font.getsize(text)
    draw.text(((width - font_width) / number, (height - font_height) / number),text,
            font= font,fill=rangem_color()) #填充字符串
    if draw_line:
        gene_line(draw,width,height)
    image = image.transform((width+20,height+10), Image.AFFINE, (1,-0.3,0,-0.1,1,0),Image.BILINEAR)  #創(chuàng)建扭曲
    image = image.filter(ImageFilter.EDGE_ENHANCE_MORE) #濾鏡,邊界加強
    # image.save('idencode.png') #保存驗證碼圖片
    image_bytes = BytesIO()
    image.save(image_bytes, format='PNG')
    return image_bytes.getvalue()

touch templates/login.html
vim templates/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶登錄</title>
    <style>
        body {
            width: 960px;
            margin: 0 auto;
        }
        .sub {
            margin: 20px 10px;
        }
    </style>
</head>
<body>
    <h1>用戶登錄</h1>
    <hr>
    <p class="hint">{{ hint }}</p>
    <form action="/login/" method="post">
        <input type="hidden" name="backurl" value="{{ backurl }}">
        {% csrf_token %}
        <div class="input">
            <label for="username">用戶名:</label>
            <input type="text" id="username" name="username">
        </div>
        <div class="input">
            <label for="password">密碼:</label>
            <input type="password" id="password" name="password">
        </div>
        <div class="input captcha">
            <label for="captcha">驗證碼:</label>
            <input type="text" id="captcha" name="captcha">
            <img src="/captcha/">
        </div>
        <div class="input">
            <input type="submit" value="登錄">
            <input type="reset" value="重置">
        </div>
    </form>
    <a href="/register">注冊新用戶</a>
</body>
</html>

4.修改views.py文件
vim voteApp/views.py

USERNAME_PATTERN = re.compile(r'\w{4,20}')

class RegisterForm(forms.ModelForm):
    repassword = forms.CharField(min_length=8, max_length=20)
    
    def clean_username(self):
        username = self.cleaned_data['username']
        if not USERNAME_PATTERN.fullmatch(username):
            raise ValidationError('用戶名由字母碱璃、數(shù)字和下劃線構成且長度為4-20個字符')
        return username
        
    def clean_password(self):
        password = self.cleaned_data['password']
        if len(password) < 8 or len(password) > 20:
            raise ValidationError('無效的密碼弄痹,密碼長度為8-20個字符')
        return to_md5_hex(self.cleaned_data['password'])

    def clean_repassword(self):
        repassword = to_md5_hex(self.cleaned_data['repassword'])
        if repassword != self.cleaned_data['password']:
            raise ValidationError('密碼和確認密碼不一致')
        return repassword

    class Meta:
        model = User
        exclude = ('no', 'regdate')

def to_md5_hex(message):
    return hashlib.md5(message.encode()).hexdigest()

def register(request):
    page, hint = 'register.html', ''
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            form.save()
            page = 'login.html'
            hint = '注冊成功,請登錄'
        else:
            hint = '請輸入有效的注冊信息'
    return render(request, page, {'hint': hint})

# 用來隨機生成一個字符串
ALL_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def gene_text(length=4):
    """成一個字符串"""
    selected_chars = random.choices(ALL_CHARS, k=length)
    return ''.join(selected_chars)

def get_captcha(request):
    """獲得驗證碼"""
    number = 4
    text = gene_text()
    image = gene_code(number,text)
    return HttpResponse(image, content_type='image/png')
    
class LoginForm(forms.Form):
    username = forms.CharField(min_length=4, max_length=20)
    password = forms.CharField(min_length=8, max_length=20)
    captcha = forms.CharField(min_length=4, max_length=4)

    def clean_username(self):
        username = self.cleaned_data['username']
        if not USERNAME_PATTERN.fullmatch(username):
            raise ValidationError('無效的用戶名')
        return username

    def clean_password(self):
        return to_md5_hex(self.cleaned_data['password'])
        
def login(request):
    hint = ''
    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            user = User.objects.filter(username=username, password=password).first()
            if user:
                return redirect('/')
            else:
                hint = '用戶名或密碼錯誤'
        else:
            hint = '請輸入有效的登錄信息'
    return render(request, 'login.html', {'hint': hint})

5.修改admin.py文件
vim voteApp/admin.py

class UserForm(forms.ModelForm):
    password = forms.CharField(min_length=8, max_length=20,
                               widget=forms.PasswordInput, label='密碼')

    def clean_username(self):
        username = self.cleaned_data['username']
        if not USERNAME_PATTERN.fullmatch(username):
            raise ValidationError('用戶名由字母嵌器、數(shù)字和下劃線構成且長度為4-20個字符')
        return username
        
    def clean_password(self):
        password = self.cleaned_data['password']
        return to_md5_hex(self.cleaned_data['password'])

    class Meta:
        model = User
        exclude = ('no', )


class UserAdmin(admin.ModelAdmin):
    list_display = ('no', 'username', 'password')
    ordering = ('no', )
    form = UserForm
    list_per_page = 10


admin.site.register(User, UserAdmin)

6.關聯(lián)urls.py文件
vim djangoVote/urls.py

path('captcha/', views.get_captcha),
path('login/', views.login, name='login'),
path('register/', views.register, name='register'),

至此肛真,注冊登錄功能完成,下一步寫邏輯爽航。


6.23

1.客戶端記住并在每次請求時帶上sessionid做法(實現(xiàn)用戶跟蹤)

  • URL重寫(所謂URL重寫就是在URL中攜帶sessionid蚓让,例如:http://www.example.com/index.html?sessionid=123456)
  • 隱藏域(隱式表單域,在提交表單的時候,可以通過在表單中設置隱藏域向服務器發(fā)送額外的數(shù)據(jù)讥珍。例如:<input type="hidden" name="sessionid" value="123456">)
  • 本地存儲(cookie历极,localStorage,sessionStorage衷佃,IndexedDB等)

2.Django對session的支持
3.完成上個項目中登錄對驗證碼的驗證
vim voteApp/views.py

def get_captcha(request):
    """獲得驗證碼"""
    number = 4
    text = gene_text()
    image = gene_code(number,text)
    request.session['captcha'] = text
    return HttpResponse(image, content_type='image/png')
    
def login(request: HttpRequest):
    """登錄"""
    hint = ''
    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            # 對驗證碼的正確性進行驗證
            captcha_from_user = form.cleaned_data['captcha']
            captcha_from_sess = request.session.get('captcha', '')
            if captcha_from_sess.lower() != captcha_from_user.lower():
                hint = '請輸入正確的驗證碼'
            else:
                username = form.cleaned_data['username']
                password = form.cleaned_data['password']
                user = User.objects.filter(username=username, password=password).first()
                if user:
                    # 登錄成功后將用戶編號和用戶名保存在session中
                    request.session['userid'] = user.no
                    request.session['username'] = user.username
                    return redirect('/')
                else:
                    hint = '用戶名或密碼錯誤'
        else:
            hint = '請輸入有效的登錄信息'
    return render(request, 'login.html', {'hint': hint})

4.創(chuàng)建首頁
touch templates/header.html
vim templates/header.html

<div class="user">
    {% if request.session.userid %}
    <span>{{ request.session.username }}</span>
    <a href="/logout">注銷</a>
    {% else %}
    <a href="/login">登錄</a>&nbsp;&nbsp;
    {% endif %}
    <a href="/register">注冊</a>
</div>

5.增加注銷功能
vim voteApp/views.py

def logout(request):
    """注銷"""
    request.session.flush()
    return redirect('/')

6.Django框架默認的session過期時間為兩周(1209600秒),可在settings.py文件中修改(# 配置會話的超時時間為1天(86400秒) SESSION_COOKIE_AGE = 86400)
7.設置關閉瀏覽器窗口時讓會話過期趟卸,不再保留用戶的任何信息(cookie中的sessionid失效),可在settings.py文件中修改(# 設置為True在關閉瀏覽器窗口時session就過期 SESSION_EXPIRE_AT_BROWSER_CLOSE = True)
8.將session放入緩存中(默認放在數(shù)據(jù)庫中),在settings.py文件中修改

# 配置將會話對象放到緩存中存儲
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
# 配置使用哪一組緩存來保存會話
SESSION_CACHE_ALIAS = 'default'

9.修改session數(shù)據(jù)默認的序列化方式,可以將默認的JSONSerializer修改為PickleSerializer
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
10.HttpRequest封裝的屬性和方法:

  • COOKIES屬性 - 該屬性包含了HTTP請求攜帶的所有cookie
  • get_signed_cookie方法 - 獲取帶簽名的cookie锄列,如果簽名驗證失敗图云,會產(chǎn)生BadSignature異常

11.HttpResponse封裝的方法:

  • set_cookie方法 - 該方法可以設置一組鍵值對并將其最終將寫入瀏覽器
  • set_signed_cookie方法 - 跟上面的方法作用相似,但是會對cookie進行簽名來達到防篡改的作用邻邮。因為如果篡改了cookie中的數(shù)據(jù)竣况,在不知道密鑰和鹽的情況下是無法生成有效的簽名,這樣服務器在讀取cookie時會發(fā)現(xiàn)數(shù)據(jù)與簽名不一致從而產(chǎn)生BadSignature異常筒严。需要說明的是丹泉,這里所說的密鑰就是我們在Django項目配置文件中指定的SECRET_KEY,而鹽是程序中設定的一個字符串鸭蛙,你愿意設定為什么都可以摹恨,只要是一個有效的字符串

12.登錄時檢查瀏覽器是否支持cookie
vim voteApp/views.py

def login(request):
    hint = ''
    if request.method == 'POST':
        if request.session.test_cookie_worked():
            request.session.delete_test_cookie()
            form = LoginForm(request.POST)
            if form.is_valid():
                # 對驗證碼的正確性進行驗證
                captcha_from_user = form.cleaned_data['captcha']
                captcha_from_sess = request.session.get('captcha', '')
                if captcha_from_sess.lower() != captcha_from_user.lower():
                    hint = '請輸入正確的驗證碼'
                else:
                    username = form.cleaned_data['username']
                    password = form.cleaned_data['password']
                    user = User.objects.filter(username=username, password=password).first()
                    if user:
                        # 登錄成功后將用戶編號和用戶名保存在session中
                        request.session['userid'] = user.no
                        request.session['username'] = user.username
                        return redirect('/')
                    else:
                        hint = '用戶名或密碼錯誤'
            else:
                hint = '請輸入有效的登錄信息'
        else:
            return HttpResponse("Please enable cookies and try again.")
    request.session.set_test_cookie()
    return render(request, 'login.html', {'hint': hint})

6.24

1.導出一個包含所有老師信息的Excel表格
vim voteApp/views.py

def export_teachers_excel(request):
    # 創(chuàng)建工作簿
    wb = xlwt.Workbook()
    # 添加工作表
    sheet = wb.add_sheet('老師信息表')
    # 查詢所有老師的信息(注意:這個地方稍后需要優(yōu)化)
    queryset = Teacher.objects.all()
    # 向Excel表單中寫入表頭
    colnames = ('姓名', '介紹', '好評數(shù)', '差評數(shù)', '學科')
    for index, name in enumerate(colnames):
        sheet.write(0, index, name)
    # 向單元格中寫入老師的數(shù)據(jù)
    props = ('name', 'detail', 'good_count', 'bad_count', 'subject')
    for row, teacher in enumerate(queryset):
        for col, prop in enumerate(props):
            value = getattr(teacher, prop, '')
            if isinstance(value, Subject):
                value = value.name
            sheet.write(row + 1, col, value)
    # 保存Excel
    buffer = BytesIO()
    wb.save(buffer)
    # 將二進制數(shù)據(jù)寫入響應的消息體中并設置MIME類型
    resp = HttpResponse(buffer.getvalue(), content_type='application/vnd.ms-excel')
    # 中文文件名需要處理成百分號編碼
    filename = quote('老師.xls')
    # 通過響應頭告知瀏覽器下載該文件以及對應的文件名
    resp['content-disposition'] = f'attachment; filename="{filename}"'
    return resp

2.映射url
vim djangoVote/urls.py
path('excel/', views.export_teachers_excel),
3.生成圖表
vim voteApp/views.py

def get_teachers_data(request):
    # 查詢所有老師的信息(注意:這個地方稍后也需要優(yōu)化)
    queryset = Teacher.objects.all()
    # 用生成式將老師的名字放在一個列表中
    names = [teacher.name for teacher in queryset]
    # 用生成式將老師的好評數(shù)放在一個列表中
    good = [teacher.good_count for teacher in queryset]
    # 用生成式將老師的差評數(shù)放在一個列表中
    bad = [teacher.bad_count for teacher in queryset]
    # 返回JSON格式的數(shù)據(jù)
    return JsonResponse({'names': names, 'good': good, 'bad': bad})
    
def get_charts(request):
    return render(request, f'teacherCharts.html')

映射url:
vim djangoVote/urls.py

path('teachers_data/', views.get_teachers_data),
path('charts/',views.get_charts),

touch templates/teacherCharts.html
vim templates/teacherCharts.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>老師評價統(tǒng)計</title>
</head>
<body>
    <div id="main" style="width: 600px; height: 400px"></div>
    <p>
        <a href="/">返回首頁</a>
    </p>
    <script src="https://cdn.bootcss.com/echarts/4.2.1-rc1/echarts.min.js"></script>
    <script>
        var myChart = echarts.init(document.querySelector('#main'))
        fetch('/teachers_data/')
            .then(resp => resp.json())
            .then(json => {
                var option = {
                    color: ['#f00', '#00f'],
                    title: {
                        text: '老師評價統(tǒng)計圖'
                    },
                    tooltip: {},
                    legend: {
                        data:['好評', '差評']
                    },
                    xAxis: {
                        data: json.names
                    },
                    yAxis: {},
                    series: [
                        {
                            name: '好評',
                            type: 'bar',
                            data: json.good
                        },
                        {
                            name: '差評',
                            type: 'bar',
                            data: json.bad
                        }
                    ]
                }
                myChart.setOption(option)
            })
    </script>
</body>
</html>

4.配置日志
vim djangoVote/settings.py

LOGGING = {
    'version': 1,
    # 是否禁用已經(jīng)存在的日志器
    'disable_existing_loggers': False,
    # 日志格式化器
    'formatters': {
        'simple': {
            'format': '%(asctime)s %(module)s.%(funcName)s: %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S',
        },
        'verbose': {
            'format': '%(asctime)s %(levelname)s [%(process)d-%(threadName)s] '
                      '%(module)s.%(funcName)s line %(lineno)d: %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S',
        }
    },
    # 日志過濾器
    'filters': {
        # 只有在Django配置文件中DEBUG值為True時才起作用
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    # 日志處理器
    'handlers': {
        # 輸出到控制臺
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'formatter': 'simple',
        },
        # 輸出到文件(每周切割一次)
        'file1': {
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'filename': 'access.log',
            'when': 'W0',
            'backupCount': 12,
            'formatter': 'simple',
            'level': 'INFO',
        },
        # 輸出到文件(每天切割一次)
        'file2': {
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'filename': 'error.log',
            'when': 'D',
            'backupCount': 31,
            'formatter': 'verbose',
            'level': 'WARNING',
        },
    },
    # 日志器記錄器
    'loggers': {
        'django': {
            # 需要使用的日志處理器
            'handlers': ['console', 'file1', 'file2'],
            # 是否向上傳播日志信息
            'propagate': True,
            # 日志級別(不一定是最終的日志級別)
            'level': 'DEBUG',
        },
    }
}

4.1 formatters是日志格式化器,其中格式占位符表示:

占位符 說明
%(name)s 記錄器的名稱
%(levelno)s 數(shù)字形式的日志記錄級別
%(levelname)s 日志記錄級別的文本名稱
%(filename)s 執(zhí)行日志記錄調(diào)用的源文件的文件名稱
%(pathname)s 執(zhí)行日志記錄調(diào)用的源文件的路徑名稱
%(funcName)s 執(zhí)行日志記錄調(diào)用的函數(shù)名稱
%(module)s 執(zhí)行日志記錄調(diào)用的模塊名稱
%(lineno)s 執(zhí)行日志記錄調(diào)用的行號
%(created)s 執(zhí)行日志記錄的時間
%(asctime)s 日期和時間
%(msecs)s 毫秒部分
%(thread)d 線程ID(整數(shù))
%(threadName)s 線程名稱
%(process)d 進程ID (整數(shù))

4.2 handlers用來指定日志處理器规惰,可用的處理器包括:

處理器 說明
logging.StreamHandler(stream=None) 可以向類似與sys.stdout或者sys.stderr的任何文件對象輸出信息
logging.FileHandler(filename, mode='a', encoding=None, delay=False) 將日志消息寫入文件
logging.handlers.DatagramHandler(host, port) 使用UDP協(xié)議睬塌,將日志信息發(fā)送到指定主機和端口的網(wǎng)絡主機上
logging.handlers.HTTPHandler(host, url) 使用HTTP的GET或POST方法將日志消息上傳到一臺HTTP 服務器
logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False) 將日志消息寫入文件,如果文件的大小超出maxBytes指定的值歇万,那么將重新生成一個文件來記錄日志
logging.handlers.SocketHandler(host, port) 使用TCP協(xié)議揩晴,將日志信息發(fā)送到指定主機和端口的網(wǎng)絡主機上

4.3 Python中定義了六個級別的日志,按照從低到高的順序依次是:NOTSET贪磺、DEBUG硫兰、INFO、WARNING寒锚、ERROR劫映、CRITICAL。

4.4 Django框架提供了如下所示的內(nèi)置記錄器:

  • django - 在Django層次結構中的所有消息記錄器
  • django.request - 與請求處理相關的日志消息刹前。5xx響應被視為錯誤消息泳赋;4xx響應被視為為警告消息
  • django.server - 與通過runserver調(diào)用的服務器所接收的請求相關的日志消息。5xx響應被視為錯誤消息喇喉;4xx響應被記錄為警告消息祖今;其他一切都被記錄為INFO
  • django.template - 與模板渲染相關的日志消息
  • django.db.backends - 有與數(shù)據(jù)庫交互產(chǎn)生的日志消息,如果希望顯示ORM框架執(zhí)行的SQL語句拣技,就可以使用該日志記錄器千诬。

5.配置Django-Debug-Toolbar
5.1 安裝Django-Debug-Toolbar
pip3 install django-debug-toolbar
5.2 修改settings.py
vim djangoVote/settings.py
5.3 修改urls.py
vim djangoVote/urls.py

if settings.DEBUG:

    import debug_toolbar

    urlpatterns.insert(0, path('__debug__/', include(debug_toolbar.urls)))

6.ORM代碼優(yōu)化
6.1 多對一關聯(lián)(如投票應用中的老師和學科)queryset = Teacher.objects.all().select_related('subject')
6.2 多對多關聯(lián)(如電商網(wǎng)站中的訂單和商品)使用prefetch_related()方法來加載關聯(lián)對象
6.3 用QuerySet的only()方法來指定需要查詢的屬性,也可以用QuerySet的defer()方法來指定暫時不需要查詢的屬性queryset = Teacher.objects.all().only('name', 'good_count', 'bad_count')
6.4 統(tǒng)計出每個學科的老師好評和差評的平均數(shù)queryset = Teacher.objects.values('subject').annotate( good=Avg('good_count'), bad=Avg('bad_count'))


6.25

1.實現(xiàn)登錄驗證(修改views.py和teacher.html文件)
vim voteApp/views.py

def praise_or_criticize(request):
    """投票"""
    if 'username' in request.session:
        try:
            tno = int(request.GET.get('tno', '0'))
            teacher = Teacher.objects.get(no=tno)
            if request.path.startswith('/praise'):
                teacher.good_count += 1
            else:
                teacher.bad_count += 1
            teacher.save()
            data = {'code': 200, 'message': '操作成功'}
        except (ValueError, Teacher.DoesNotExist):
            data = {'code': 404, 'message': '操作失敗'}
    else:
        data = {'code': 401, 'message': '請先登錄'}
    return JsonResponse(data)

vim templates/teacher.html

<script>
    $(() => {
        $('.comment > a').on('click', (evt) => {
            evt.preventDefault()
            let a = $(evt.target)
            $.getJSON(a.attr('href'), (json) => {
                if (json.code == 200) {
                    let span = a.next()
                    span.text(parseInt(span.text()) + 1)
                } else if (json.code == 401) {
                    window.location.href = '/login/?backurl=' + location.href
                } else {
                    alert(json.message)
                }
            })
        })
    })
</script>

2.Django中間件

  • 中間件是安插在Web應用請求和響應過程之間的組件膏斤,它在整個Web應用中扮演了攔截過濾器的角色徐绑,通過中間件可以攔截請求和響應,并對請求和響應進行過濾(簡單的說就是執(zhí)行額外的處理)莫辨。
  • Django中間件在settings.py文件MIDDLEWARE
    1). django.middleware.common.CommonMiddleware:基礎設置中間件傲茄,可以處理以下一些配置參數(shù)毅访。
    • DISALLOWED_USER_AGENTS - 不被允許的用戶代理(瀏覽器)
    • APPEND_SLASH - 是否追加/
    • USE_ETAG - 瀏覽器緩存相關

2). django.middleware.security.SecurityMiddleware:安全相關中間件,可以處理和安全相關的配置項烫幕。
+ SECURE_HSTS_SECONDS - 強制使用HTTPS的時間
+ SECURE_HSTS_INCLUDE_SUBDOMAINS - HTTPS是否覆蓋子域名
+ SECURE_CONTENT_TYPE_NOSNIFF - 是否允許瀏覽器推斷內(nèi)容類型
+ SECURE_BROWSER_XSS_FILTER - 是否啟用跨站腳本攻擊過濾器
+ SECURE_SSL_REDIRECT - 是否重定向到HTTPS連接
+ SECURE_REDIRECT_EXEMPT - 免除重定向到HTTPS

3). django.contrib.sessions.middleware.SessionMiddleware:會話中間件
4). django.middleware.csrf.CsrfViewMiddleware:通過生成令牌俺抽,防范跨請求份偽的造中間件
5). django.middleware.clickjacking.XFrameOptionsMiddleware:通過設置請求頭參數(shù),防范點擊劫持攻擊的中間件
6). 在請求的過程中较曼,上面的中間件會按照1-5的順序執(zhí)行,然后是URL解析振愿,最后請求才會來到視圖函數(shù)捷犹;在響應的過程中,上面的中間件會按照5-1的順序執(zhí)行冕末,與請求時中間件執(zhí)行的順序正好相反

3.自定義中間件(實現(xiàn)用戶登錄驗證的功能)
3.1創(chuàng)建中間件文件
touch voteApp/middlewares.py
3.2修改中間件文件
vim voteApp/middlewares.py

from django.http import JsonResponse
from django.shortcuts import redirect

# 需要登錄才能訪問的資源路徑
LOGIN_REQUIRED_URLS = {
    '/excel/', '/teachers_data/','/charts/'
}


def check_login_middleware(get_resp):

    def wrapper(request, *args, **kwargs):
        # 請求的資源路徑在上面的集合中
        if request.path in LOGIN_REQUIRED_URLS:
            # 會話中包含userid則視為已經(jīng)登錄
            if 'userid' not in request.session:
                # 判斷是不是Ajax請求
                if request.is_ajax():
                    # Ajax請求返回JSON數(shù)據(jù)提示用戶登錄
                    return JsonResponse({'code': 10003, 'hint': '請先登錄'})
                else:
                    backurl = request.get_full_path()
                    # 非Ajax請求直接重定向到登錄頁
                    return redirect(f'/login/?backurl={backurl}')
        return get_resp(request, *args, **kwargs)

    return wrapper

3.3修改配置文件萍歉,激活中間件使其生效
vim djangoVote/setting
'voteApp.middlewares.check_login_middleware',
中間件執(zhí)行的順序是非常重要的,對于有依賴關系的中間件必須保證被依賴的中間件要置于依賴它的中間件的前面档桃,就好比我們剛才自定義的中間件要放到SessionMiddleware的后面枪孩,因為我們要依賴這個中間件為請求綁定的session對象才能判定用戶是否登錄


6.26

1.前后端分離(提升開發(fā)效率/增強代碼的可維護性/支持多終端和服務化架構)
2.返回Json數(shù)據(jù)
eg:

def show_subjects(request):
    # 通過循環(huán)遍歷查詢學科得到的QuerySet對象
    queryset = Subject.objects.all()
    # 創(chuàng)建學科列表容器
    subjects = []
    # 將每個學科的數(shù)據(jù)處理成一個字典,在將字典保存在容器中
    for subject in queryset:
        subjects.append({
            'no': subject.no,
            'name': subject.name,
            'intro': subject.intro,
            'isHot': subject.is_hot
        })
    # 用JsonResponse完成對列表的序列化
    return JsonResponse(subjects, safe=False)
    # 由于JsonResponse序列化的是一個列表而不是字典藻肄,所以需要指定safe參數(shù)的值為False才能完成對subjects的序列化蔑舞,否則會產(chǎn)生TypeError異常。

3.使用bpmappers對數(shù)據(jù)序列化

  • 安裝pip3 install bpmappers
  • 編寫映射器(實現(xiàn)對象到字典轉換)
    vim voteApp/views.py
from bpmappers.djangomodel import ModelMapper
from voteApp.models import Subject

class SubjectMapper(ModelMapper):
   
    class Meta:
        model = Subject
        
def show_subjects(request):
    queryset = Subject.objects.all()
    subjects = []
    for subject in queryset:
        subjects.append(SubjectMapper(subject).as_dict())
    return JsonResponse(subjects, safe=False)
  • 修改鍵名嘹屯,刪除屬性
    vim voteApp/views.py
from bpmappers import RawField
from bpmappers.djangomodel import ModelMapper

from voteApp.models import Subject


class SubjectMapper(ModelMapper):
    # 修改鍵名
    isHot = RawField('is_hot')

    class Meta:
        model = Subject
        # 刪除 
        exclude = ('create_date', 'is_hot')

4.使用Vue.js渲染頁面(重新改寫subjects.html頁面攻询,使用Vue.js來渲染頁面)
vim templates/subjects.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>學科</title>
</head>
<body>
    <h1>所有學科</h1>
    <hr>
    <div id="app">
        <div v-for="subject in subjects">
            <h3>
                <a :href="getTeachersHref(subject.no)">{{ subject.name }}</a>
                <img v-if="subject.isHot" src="/static/images/hot.png" width="32">
            </h3>
            <p>{{ subject.intro }}</p>
        </div>
    </div>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                subjects: []
            },
            created() {
                fetch('/subjects/')
                    .then(resp => resp.json())
                    .then(json => this.subjects = json)
            },
            methods: {
                getTeachersHref(sno) {
                    return `/static/teachers.html/?sno=${sno}`
                }
            }
        })
    </script>
</body>
</html>

動靜分離,靜態(tài)資源通過Nginx或Apache服務器進行部署州弟,生成動態(tài)內(nèi)容的Python程序部署在uWSGI或者Gunicorn服務器上钧栖,對動態(tài)內(nèi)容的請求由Nginx或Apache路由到uWSGI或Gunicorn服務器上。


6.28-7.9(6.27休息一天)

沒課件了婆翔,看Django的翻譯文檔吧拯杠。
由于內(nèi)容過長,分成上下兩部分吧

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啃奴,一起剝皮案震驚了整個濱河市潭陪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纺腊,老刑警劉巖畔咧,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揖膜,居然都是意外死亡誓沸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門壹粟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拜隧,“玉大人宿百,你說我怎么就攤上這事『樘恚” “怎么了垦页?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長干奢。 經(jīng)常有香客問我痊焊,道長,這世上最難降的妖魔是什么忿峻? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任薄啥,我火速辦了婚禮,結果婚禮上逛尚,老公的妹妹穿的比我還像新娘垄惧。我一直安慰自己,他們只是感情好绰寞,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布到逊。 她就那樣靜靜地躺著,像睡著了一般滤钱。 火紅的嫁衣襯著肌膚如雪觉壶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天菩暗,我揣著相機與錄音掰曾,去河邊找鬼。 笑死停团,一個胖子當著我的面吹牛旷坦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播佑稠,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼秒梅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了舌胶?” 一聲冷哼從身側響起捆蜀,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎幔嫂,沒想到半個月后辆它,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡履恩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年锰茉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片切心。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡飒筑,死狀恐怖片吊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情协屡,我是刑警寧澤俏脊,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站肤晓,受9級特大地震影響爷贫,放射性物質發(fā)生泄漏。R本人自食惡果不足惜材原,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一沸久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧余蟹,春花似錦、人聲如沸子刮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挺峡。三九已至葵孤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間橱赠,已是汗流浹背尤仍。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留狭姨,地道東北人宰啦。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像饼拍,于是被迫代替她去往敵國和親赡模。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容