Django框架

軟件框架

定義

在這里插入圖片描述

一個軟件是由其中各個軟件模塊組成的栏豺,每一個模塊都有特定的功能,模塊與模塊之間通過相互配合來完成軟件的開發(fā)搅裙。

軟件框架是針對某一類軟件設(shè)計問題而產(chǎn)生的

Django遵循的是MVC思想

MVC框架

MVC的產(chǎn)生理念:分工请毛,讓專門的人去做專門的事情(比如:輸入、處理鼓蜒、輸出)

MVC的核心思想:解耦

MVC是三個模塊的簡稱:

  • M:model痹换,模型,和數(shù)據(jù)庫進(jìn)行交互
  • V:View都弹,視圖娇豫,產(chǎn)生html頁面
  • C:Controller,控制器畅厢,接收請求冯痢,進(jìn)行處理,與M和V進(jìn)行交互框杜,返回應(yīng)答

以通過瀏覽器注冊用戶信息為例:


在這里插入圖片描述

Django簡介

Django浦楣,發(fā)音為[`d???ɡ??],是用python語言寫的開源web開發(fā)框架咪辱,并遵循MVC設(shè)計振劳。

MVT

Django是遵循MVC的一個Web框架,但是他有自己的一個名字油狂,叫做MVT

快速開發(fā)DRY原則历恐。Do not repeat yourself。不要自己去重復(fù)一些工作

M:Model选调,模型夹供,和數(shù)據(jù)庫進(jìn)行交互,與MVC中的M功能相同
V:View仁堪,視圖哮洽,接收請求,進(jìn)行處理弦聂,與M和T交互鸟辅,返回應(yīng)答,與MVC中的C功能相同
T:template莺葫,模板匪凉,產(chǎn)生html頁面,和MVC終的V功能相同

MVT的各部分功能:

在這里插入圖片描述
django官方網(wǎng)站:https://www.djangoproject.com/

虛擬環(huán)境

在Linux上捺檬,如果用pip3安裝的包再层,會安裝在/user/local/lib/python3.xx/dis-packages下面。當(dāng)安裝同一個包的不同版本的時候堡纬,后安裝的版本會把原來安裝的版本覆蓋掉聂受。

如何解決這個問題?
使用虛擬環(huán)境烤镐,所謂虛擬環(huán)境蛋济,就是真實(shí)python環(huán)境的一個復(fù)制版本。在虛擬環(huán)境中使用的python是復(fù)制的python炮叶,安裝python包也是安裝在復(fù)制的python中

ps:如果是在pycharm里的設(shè)置里面安裝的碗旅,而不是用pip命令安裝的渡处,會默認(rèn)安裝在一個虛擬環(huán)境里面

Linux下安裝虛擬環(huán)境的命令

  • sudo pip install virtualenv 安裝虛擬環(huán)境

  • sudo pip install virtualenvwrapper 安裝虛擬環(huán)境擴(kuò)展包

  • 編輯家目錄下面的.bashrc文件,添加如下兩行內(nèi)容

    • export WORKON_HOME=$HOME/.virtualenvs
    • source /user/local/bin/virtualenvwrapper.sh
  • 使用source .bashrc使其生效

  • 創(chuàng)建python2的虛擬環(huán)境:mkvirtualenv 虛擬環(huán)境名稱

  • 創(chuàng)建python3的虛擬環(huán)境:mkvirtualenv -p python3 虛擬環(huán)境名

  • 進(jìn)入虛擬環(huán)境工作:workon 虛擬環(huán)境名

  • 查看機(jī)器上有多少個虛擬環(huán)境:workon 空格 + 兩個tab鍵

  • 退出虛擬環(huán)境:deactivate

  • 刪除虛擬環(huán)境:rmvirtualenv 虛擬環(huán)境名

在虛擬環(huán)境中的一些命令:

  • pip list 查看安裝了的包祟辟,pip freeze也可以
  • pip install 包的名字(如果要指定版本號医瘫,再緊跟==版本號),如果使用sudo安裝川尖,仍然是安全到全局

Windows環(huán)境安裝虛擬環(huán)境

  • pip list查看是否已經(jīng)安裝virtualenv
  • 如果沒有安裝過:pip install virtualenv登下,安裝成功后,會提示:Success fully installed virtualenv-xxx
  • 在一個目錄下創(chuàng)建虛擬環(huán)境:virtualenv 虛擬環(huán)境的名字
  • 進(jìn)入虛擬環(huán)境所在目錄的scripts叮喳,查看scripts目錄結(jié)構(gòu),可以看到激活虛擬環(huán)境的命令:activate.bat
  • 執(zhí)行activate命令

項(xiàng)目創(chuàng)建

django-admin startproject 項(xiàng)目名字(注意:需要先進(jìn)入虛擬環(huán)境缰贝,Linux和Windows相同)

創(chuàng)建成功后馍悟,目錄結(jié)構(gòu)如下:

在這里插入圖片描述

其中:

  • __init__.py說明其所在路徑是一個python的包
  • settings.py是項(xiàng)目的配置文件,比如項(xiàng)目要使用哪個數(shù)據(jù)庫剩晴,就在里面配置
  • urls.py url:在訪問網(wǎng)站時锣咒,我們輸入的網(wǎng)站就是一個url的地址。urls.py文件是進(jìn)行url路由的配置(當(dāng)我們輸入一個地址后赞弥,他怎么給我們找到對應(yīng)的處理函數(shù)是誰)
  • wsgi.py Django是遵循wsgi協(xié)議的框架毅整,wsgi.py就是web服務(wù)器和django交互的一個入口
  • manage.py 是我們項(xiàng)目的管理文件,是一個可執(zhí)行文件绽左,通過該文件悼嫉,我們可以管理整個項(xiàng)目

創(chuàng)建django應(yīng)用

一個項(xiàng)目由很多個應(yīng)用組成,每一個應(yīng)用完成一個功能模塊

創(chuàng)建應(yīng)用的命令如下:python manage.py startapp 應(yīng)用名

每創(chuàng)建一個應(yīng)用拼窥,里面就會有如下文件:


在這里插入圖片描述

其中:

  • __init__.py說明該應(yīng)用是一個python模塊
  • models.py中寫和數(shù)據(jù)庫相關(guān)的內(nèi)容
  • views.py 接收請求戏蔑,進(jìn)行處理,與M和T進(jìn)行交互鲁纠,返回應(yīng)答总棵。定義處理函數(shù)(在django中稱視圖函數(shù))
  • tests.py寫測試代碼的文件,不怎么需要關(guān)心
  • admin.py跟網(wǎng)站的后臺管理相關(guān)的文件
  • migrations文件夾:存放由模型類生成的遷移文件

在我們建立應(yīng)用之后改含,必須建立應(yīng)用和項(xiàng)目之間的聯(lián)系情龄,即:對應(yīng)用進(jìn)行注冊:在settings.py中修改installed_apps配置項(xiàng),eg:注冊booktest應(yīng)用

在這里插入圖片描述

運(yùn)行項(xiàng)目

運(yùn)行一個web項(xiàng)目捍壤,就需要一個web服務(wù)器骤视,而django本身給我們提供了一個web服務(wù)器,使用python manage.py runsevser運(yùn)行該服務(wù)器白群,然后即可根據(jù)提示用瀏覽器訪問

ORM

O:object尚胞,對象
R:relations,關(guān)系
M:mapping帜慢,映射

ORM的作用:建立類和表的對應(yīng)關(guān)系

ORM讓我們能夠通過對類和對象的操作實(shí)現(xiàn)對表的操作笼裳,就不需要再去寫sql語句唯卖。這是元類的一種最經(jīng)典的應(yīng)用

在創(chuàng)建的項(xiàng)目文件夾下的models.py文件中,我們設(shè)計和表對應(yīng)的類躬柬,這個類被稱做模型類

ORM的另一個作用:根據(jù)設(shè)計的類生成數(shù)據(jù)庫中的表

模型(M)

模型類設(shè)計和表生成

模型類設(shè)計

在項(xiàng)目文件夾下的models.py文件中拜轨,比如我們定義一個圖書類

from django.db import models
# Create your models here.
class BookInfo(models.Model):
    # 必須繼承了Model類之后,他才是一個模型類
    # 模型類的名字就對應(yīng)的表的名字為:應(yīng)用名_小寫的模型類名
    # 模型類中的類屬性就對應(yīng)于表中的一個字段(列)
    btitle = models.CharField(max_length=20) #書名
    #通過models.CharField體現(xiàn)btitle的類型是一個字符串,max_length制定字符串的最大長度
    bpub_date = models.DateField()  #出版日期
    #models.DateField說明其是一個日期類型
    
    #在django中允青,id不需要我們定義橄碾,他會幫我們自動生成

模型類的字段屬性和選項(xiàng)

模型類屬性命名限制

  • 不能是python關(guān)鍵字
  • 不允許使用連續(xù)的下劃線,不是由django的查詢方式?jīng)Q定的
  • 定義屬性時需要指定字段類型颠锉,通過字段類型的參數(shù)指定選擇法牲,語法如下: 屬性名 = models.字段類型(選項(xiàng))

字段類型

使用時需要引入django.db.models包

  • AutoField 自動增長的IntegerField,通常不用指定琼掠,不指定時django會自動創(chuàng)建屬性名為id的自動增長屬性拒垃,在遷移文件中可以查看到

  • BooleanField 布爾字段,值為True或False

  • NullBooleanField 支持Null瓷蛙,True悼瓮,F(xiàn)alse三種值

  • CharField(max_length=最大長度) 字符串,參數(shù)max_length指定最大字符個數(shù)艰猬,必須指定横堡,不然報錯

  • TextField 大文本字段,一般超過4k個字

  • IntegerField 整數(shù)

  • DecimalField(max_digits=None, decimal_places=None) 十進(jìn)制浮點(diǎn)數(shù)冠桃,第一個參數(shù)表示總位命贴,第二個參數(shù)表示小數(shù)位數(shù)

  • FloatField 浮點(diǎn)數(shù),參數(shù)同上腊满。注意:float的精確度比decimal小

  • DateField([auto_now=False, auto_now_add=False]) 日期套么,有兩個可選參數(shù):

    • auto_now 表示每次保存對象時,自動設(shè)置該字段為當(dāng)前時間碳蛋,用于“最后一次修改”的時間戳胚泌,它總是使用當(dāng)前日期,默認(rèn)為false
    • auto_now_add 表示當(dāng)對象第一次被創(chuàng)建時自動設(shè)置當(dāng)前時間肃弟,用于創(chuàng)建的時間戳玷室,它總是使用當(dāng)前日期,默認(rèn)false
    • 兩個參數(shù)是相互排斥的笤受,不能同時使用
  • TimeField 時間參數(shù)同DateField

  • DateTimeField 日期時間穷缤,參數(shù)同上

  • FileField 上傳文件字段

  • ImageField 繼承于FileField,對上傳的內(nèi)容進(jìn)行校驗(yàn)箩兽,確保是有效的圖片

選項(xiàng)

作為Field()中的參數(shù)

通過選項(xiàng)實(shí)現(xiàn)的字段的約束津肛,選項(xiàng)如下:

  • default 默認(rèn)值。設(shè)置默認(rèn)值
  • primary_key 若為True汗贫,則該字段會成為模型的主鍵字段身坐,默認(rèn)值是false秸脱,一般作為AutoField的選項(xiàng)使用
  • unique 唯一性約束,如果為True部蛇,這個字段在表中必須有唯一值摊唇,默認(rèn)值是False
  • db_index 若值為True,則在表中會為這個字段創(chuàng)建索引涯鲁,默認(rèn)值為False
  • db_column 字段的名稱巷查,如果未指定,則使用屬性的名稱
  • null 如果為True抹腿,表示允許為空岛请,默認(rèn)值是False
  • blank 如果為True,則該字段允許為空白幢踏,默認(rèn)值是False

更多的可以見官方文檔

對比:null是數(shù)據(jù)庫的概念髓需,blank是后臺管理頁面表單驗(yàn)證范疇的

注意:當(dāng)修改模型類之后,如果添加的選項(xiàng)不影響表的結(jié)構(gòu)房蝉,則不需要重新做遷移,eg:blank和default

模型類生成表

一微渠、 生成遷移文件

遷移文件是根據(jù)模型類生成的搭幻,生成的遷移文件存放在migrations文件夾下

命令:python manage.py makemigrations

二、執(zhí)行遷移生成表

命令:python manage.py migrate

根據(jù)遷移文件生成表

注意:django默認(rèn)使用的數(shù)據(jù)庫是sqlite3逞盆,在項(xiàng)目文件夾下檀蹋,與項(xiàng)目同名的文件夾下的settings.py文件中DATABASES字段處可以看到

當(dāng)文件遷移后,我們就可以在項(xiàng)目文件夾下看到一個名為db.sqlite3的文件云芦,即我們的數(shù)據(jù)庫文件俯逾,可以直接使用相應(yīng)軟件打開

通過模型類操作數(shù)據(jù)表

  • 使用python manage.py shell進(jìn)入項(xiàng)目終端
  • from booktest.models import BookInfo (from 應(yīng)用名.models import 自己定義的類的名字)
  • 創(chuàng)建類的對象:b = BookInfo()
  • 增加實(shí)例屬性(注意:這個實(shí)例屬性的名字必須和類屬性的名字一樣):b.btitle = "天龍八部"
  • from datetime import date
  • b.bpub_date = date(1990,1,1)
  • 然后就把這個實(shí)例屬性里面保存的數(shù)據(jù)添加到數(shù)據(jù)庫:b.save(),注意:這個方法是繼承自models.Model
  • 用 模型類名.objects查看對應(yīng)表里面的數(shù)據(jù)(注意:是模型類名舅逸,而不是上面的變量名b)桌肴,eg:查看id=1的記錄:b2 = BookInfo.objects.get(id=1),b2是一個BookInfo類的對象琉历。即:把查出來的數(shù)據(jù)是保存在一個對象里面坠七,然后可以用類似:b2.btitle查看btitle對應(yīng)的數(shù)據(jù)
  • 更改數(shù)據(jù):b2.bpub_date = date(1990,10,10),即:直接更改查詢的對象的屬性值即可旗笔,然后用b2.save()將保存同步到數(shù)據(jù)庫
  • 如何刪除一條記錄:b2.delete()

建立兩張表之間的關(guān)系:外鍵

from django.db import models
# Create your models here.
class BookInfo(models.Model):
    # 必須繼承了Model類之后彪置,他才是一個模型類
    # 模型類中的類屬性就對應(yīng)于表中的一個字段(列)
    btitle = models.CharField(max_length=20) #書名
    #通過models.CharField體現(xiàn)btitle的類型是一個字符串,max_length制定字符串的最大長度
    bpub_date = models.DateField()  #出版日期
    #models.DateField說明其是一個日期類型

    #在django中,id不需要我們定義蝇恶,他會幫我們自動生成

class HeroInfo(models.Model):
    hname = models.CharField(max_length=20) #名字
    hgender = models.BooleanField(default=False)    #性別拳魁,布爾類型,default制定默認(rèn)值
    hcomment = models.CharField(max_length=128) #備注
    # 在有一對多的關(guān)系的兩個類中撮弧,需要在“多”的類中定義外鍵潘懊,建立“一”和“多”的關(guān)系

    # 關(guān)系屬性對應(yīng)的表的字段名格式:關(guān)系屬性名_id
    hbook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)   # 建立了圖書類和英雄人物類之間的關(guān)系姚糊,注意:如果兩個類不在一個應(yīng)用里面,則需要寫成 應(yīng)用.類名卦尊,eg:booktest.BookInfo

注意:往“多”類的屬性里面賦值的時候叛拷,相關(guān)聯(lián)屬性其對應(yīng)值必須是與其關(guān)聯(lián)的類的對象,eg:


在這里插入圖片描述

對該屬性進(jìn)行查看岂却,發(fā)現(xiàn)其是一對象:


在這里插入圖片描述
在這里插入圖片描述

查看與“一”相關(guān)聯(lián)的“多”的信息(eg:此處與圖書相關(guān)聯(lián)的英雄的信息)
在這里插入圖片描述

注意:這里的heroinfo是小寫

查詢表中的所有內(nèi)容:類名.objects.all()忿薇,返回的是一個列表,其中的元素為每一條數(shù)據(jù)的對象

后臺管理

在所創(chuàng)建應(yīng)用的對應(yīng)文件夾下躏哩,有一個admin.py署浩,(eg:本案例中為:/myProject/booktest/admin.py)通過它,我們實(shí)現(xiàn)后臺的管理

步驟:

  • 本地化

    • 語言和時區(qū)的本地化:修改settings.py文件


      在這里插入圖片描述
  • 登錄管理頁面需要有一個管理員的賬戶:創(chuàng)建管理員:python manage.py createsuperuser

  • 使用:python manage.py runserver啟動服務(wù)器扫尺,然后就可以通過瀏覽器進(jìn)行管理筋栋,127.0.0.1:8000/admin,然后就可以幫助我們管理數(shù)據(jù)庫里面的數(shù)據(jù)正驻。注意:服務(wù)器的默認(rèn)端口是8000弊攘,但是我們也可以在運(yùn)行時直接指定:python manage.py runserver 127.0.0.1:8001


    在這里插入圖片描述
  • 注冊模型類

    在應(yīng)用下的admin.py中注冊模型類,告訴django框架根據(jù)注冊的模型類來生成對應(yīng)表管理頁面

admin文件:


在這里插入圖片描述

注冊后的管理界面:


在這里插入圖片描述
但是注意:表中的記錄名為對應(yīng)對象的字符串姑曙,如何使其顯示我們能夠看懂的內(nèi)容襟交?答:重寫str方法,eg:
在這里插入圖片描述
在這里插入圖片描述
  • 自定義管理頁面:自定義模型管理類伤靠。模型管理類就是告訴django在生成的管理頁面上顯示哪些內(nèi)容(比如捣域,我們讓其在瀏覽 器中顯示圖書名稱的同時顯示出版時間)
class BookInfoAdmin(admin.ModelAdmin):
    # 自定義模型管理類,名字可以隨便取宴合,但是通常是:表的名字+Admin
    list_display = ['id','btitle','bpub_date']  # 固定寫法焕梅,列表中寫要在頁面中顯示的內(nèi)容
    # 同時,在注冊的時候卦洽,我們需要讓該模型類知道自己的管理類是誰
admin.site.register(BookInfo, BookInfoAdmin)    # 注意贞言,該語句不能分兩次寫,否則會報錯

視圖(V)

在django中逐样,通過瀏覽器去請求一個頁面的時候蜗字,是使用視圖函數(shù)來處理這個請求的,視圖函數(shù)處理后脂新,要給瀏覽器返回頁面內(nèi)容

視圖函數(shù)的使用

一挪捕、定義視圖函數(shù)

在應(yīng)用下的views.py中,eg:定義一個名為index的視圖函數(shù)(注意:視圖函數(shù)必須有一個參數(shù):request)

from django.http import HttpResponse
def index(request):
    # 視圖函數(shù)必須有一個request參數(shù)争便,它是一個HttpRequest對象
    # 當(dāng)用戶輸入http://127.0.0.1:8000/index的時候级零,要給瀏覽器返回一個內(nèi)容
    # 視圖的作用,就是在里面會進(jìn)行處理,如果要用到數(shù)據(jù)庫奏纪,就與M交互鉴嗤,如果要產(chǎn)生頁面,就與T交互
    # 視圖函數(shù)必須返回一個HttpResponse對象序调,需要從django.http中導(dǎo)入
    # 所謂要產(chǎn)生頁面就與T(template)進(jìn)行交互:template就是一段html代碼醉锅,當(dāng)V拿到tempalte后,
    # 將里面的部分?jǐn)?shù)據(jù)用從M(數(shù)據(jù)庫)拿來的數(shù)據(jù)進(jìn)行替換发绢,然后返回硬耍,瀏覽器就可以直接解析這段html代碼從而在瀏覽器上顯示對應(yīng)內(nèi)容
    return HttpResponse("<h1>hello django!</h1>")
    # 我們知道,一個地址對應(yīng)一個處理函數(shù)边酒,那么如何讓django知道哪個地址是對應(yīng)哪個處理函數(shù)经柴?
    # 答:進(jìn)行url路由的配置

二、進(jìn)行url的配置

首先我們要在應(yīng)用對應(yīng)的目錄下建立urls.py文件墩朦,然后在其中創(chuàng)建一個列表坯认,如下:

from django.conf.urls import url
from booktest import views
urlpatterns = [
    # 通過url函數(shù)設(shè)置url路由的配置項(xiàng)
    url(r'^index', views.index) #建立/index和視圖index之間的關(guān)系
]

同時,我們也需要在項(xiàng)目的urls里面添加配置項(xiàng)

from django.contrib import admin
from django.urls import path,include
from django.conf.urls import url

urlpatterns = [
    path('admin/', admin.site.urls),    # 配置項(xiàng)
    url(r'^', include('booktest.urls')) # 將booktest應(yīng)用中的urls文件包含進(jìn)來
    # url函數(shù)第一個參數(shù)是一個正則表達(dá)式
]

效果圖如下:


在這里插入圖片描述

流程分析:

  • 當(dāng)我們在瀏覽器中輸入127.0 .0.1:8000/index的時候氓涣,django拿到的是/index

  • 然后就會拿這一部分去查找對應(yīng)的視圖

    • 先到項(xiàng)目的urls文件里面去查找牛哺,拿該字符串與urlpatterns中每一項(xiàng)的第一個參數(shù)(正則表達(dá)式)進(jìn)行匹配
    • 如果匹配上了(由于我們在第二項(xiàng)只匹配了開頭,那么無論匹配什么都能成功)劳吠,就會執(zhí)行后面的動作荆隘,于是django就拿著字符串到應(yīng)用中去與應(yīng)用中的urls進(jìn)行匹配,但是注意:在整個匹配過程中赴背,/index中,最前面的/不參與正則的匹配晶渠,匹配成功凰荚。(在進(jìn)行匹配時,會去掉匹配成功的部分褒脯,比如此處便瑟,我們在項(xiàng)目的urls中進(jìn)行匹配時,由于只匹配了個開頭番川,沒有具體的數(shù)據(jù)到涂,所以django還是拿著index去應(yīng)用的urls中匹配,如果我們假設(shè)在項(xiàng)目的urls中匹配到了i颁督,那么django就只會拿著ndex去應(yīng)用中匹配)
    • 然后一看對應(yīng)的是一個視圖践啄,django就會去調(diào)用這個視圖,然后獲得返回的數(shù)據(jù)("<h1>hello django!</h1>"
    • 于是瀏覽器就可以進(jìn)行顯示
在這里插入圖片描述

注意:在應(yīng)用的urls文件中進(jìn)行url匹配的時候谆刨,一定要嚴(yán)格匹配開頭結(jié)尾沧奴,避免出現(xiàn)意外

模板(T)

django中的模板不僅僅是個html文件鹊奖,還可以在其中定義變量渐逃,也可以寫類似于編程語言的語句

模板文件的使用

  • 創(chuàng)建模板文件夾(通常是在項(xiàng)目文件夾下創(chuàng)建templates)

  • 配置模板目錄(在項(xiàng)目的settings.py文件下)伐谈,如下:


    在這里插入圖片描述
  • 使用模板文件

    • 加載模板文件:去模板目錄下面獲取html文件的內(nèi)容烂完,得到一個模板對象(通常,不同的應(yīng)用會用到不同的模板文件诵棵,所以我們會再在templates下面建立與應(yīng)用名同名的文件夾抠蚣,用以存儲該應(yīng)用用到的模板文件)
    • 定義模板上下文:向模板文件傳遞數(shù)據(jù),即:如果模板中使用了變量履澳,需要將變量的數(shù)據(jù)給他
    • 模板渲染嘶窄,讀出變量后,將變量的位置替換掉奇昙,即得到一個標(biāo)準(zhǔn)的html文件

eg:

模板文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板文件</title>
</head>
<body>
    <h1>這是一個模板文件</h1>
    <p>我在這里使用了模板變量护侮,在模板中使用變量,如果不是在代碼段內(nèi)储耐,就要使用兩個花括號括起來:{{content}}</p>
    <ul>模板中的代碼段要寫在兩個%中間:{% for i in list %}
        <li>{{i}}</li>
        {% endfor %}
<!--        在模板中羊初,如果使用代碼,有開始就一定有結(jié)束什湘,比如endfor长赞,比如endif-->
    </ul>
</body>
</html>

應(yīng)用程序中的views文件

# -*- coding:utf-8 -*-
from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse
from django.template import loader,RequestContext
def index(request):
    # # 1. 加載模板文件
    # temp = loader.get_template('booktest/index.html') #注意:這里的路徑是相對與templates的
    # # 返回值是一個模板對象
    #
    # # 2. 定義模板上下文:給模板文件傳數(shù)據(jù)。所謂定義模板上下文闽撤,就是創(chuàng)建一個RequestContext對象
    # context = RequestContext(request, {})    # RequestContext的第一個對象需要是一個request
    # context.push(locals())
    # # 要給模板文件傳遞的數(shù)據(jù)就放在第二個參數(shù)里面得哆,其是一個字典,通過鍵-值對的方式傳遞
    # # 由于我們這里沒有用到變量哟旗,所以傳空字典即可
    #
    # # 3. 模板渲染:產(chǎn)生標(biāo)準(zhǔn)的html內(nèi)容
    # # 模板對象temp里面有一個render方法贩据,能夠把RequestContext對象中對應(yīng)的位置替換成對應(yīng)的值
    # # 然后返回替換后的內(nèi)容:一個標(biāo)準(zhǔn)的html文件
    # res_html = temp.render(request=request,context=locals())
    # # 4. 返回給瀏覽器
    #
    # return HttpResponse(res_html)
    return render(request,'booktest/index.html',{"content":"hello world", "list": list(range(10))})

    # 注意:實(shí)際上以上幾個過程都已經(jīng)被進(jìn)一步封裝到了render中,我們可以直接寫成:render(request, '/booktest/index.html',{})
    # 第三個參數(shù)是我們要傳遞給模板文件的數(shù)據(jù)闸餐,但是建議自己手動替換饱亮。如果不傳的話也可以直接不寫

效果圖:

在這里插入圖片描述

知識補(bǔ)充

  • 在配置url的時候,只要對正則表達(dá)式分組舍沙,django就會將該分組作為參數(shù)傳遞給后面的參數(shù)近上,eg:
from django.conf.urls import url
from booktest import views
urlpatterns = [
    url(r'^index', views.index),
    url(r'^show_books$', views.show_books), 
    url(r'^show_books/(\d+)$', views.detail),
    # 在配置url的時候,只要對正則表達(dá)式分組拂铡,django就會將該分組作為參數(shù)傳遞給后面的參數(shù)壹无,這里就是將匹配到的數(shù)字傳遞給views.detail函數(shù)
    # ps:新版django可以使用path來代替url
]
  • 模板文件中 for循環(huán)里面的empty項(xiàng),當(dāng)要遍歷的東西為空的時候感帅,就執(zhí)行empy
<h1>{{ book.btitle }}</h1>
英雄信息如下:<br>
<ul>
    {% for hero in heros %}
        <li>{{hero.hname}}---{{hero.hcomment}}</li>
    {% empty %}
    <!-- empty:用在for循環(huán)中斗锭,如果遍歷東西為空,就會執(zhí)行這里的東西 -->
    <li>沒有英雄信息</li>
    {% endfor %}
</ul>

Django中數(shù)據(jù)庫的配置

在django中留瞳,通過方便的配置就可以進(jìn)行數(shù)據(jù)庫的切換拒迅,直接更改項(xiàng)目的settings文件

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        """使用mysql數(shù)據(jù)庫"""
        """注意:在使用mysql數(shù)據(jù)庫的時候需要使用一個叫MySQLdb的模塊,我們直接安裝pymysql即可"""
        """然后在項(xiàng)目文件夾下的settings文件中加上如下代碼:
            import pymysql
            pymysql.install_as_MySQLdb()
        """
        'ENGINE': 'django.db.backends.mysql',   #說明使用mysql數(shù)據(jù)庫
        'NAME': 'bj18',    #說明要使用的數(shù)據(jù)庫的名字,注意璧微,數(shù)據(jù)庫必須事先手動創(chuàng)建
        # 配置用戶名和密碼
        'USER': 'root',
        'PASSWORD': "",
        'HOST': 'localhost',    #指定數(shù)據(jù)庫所在的ip地址作箍,因?yàn)橥ǔN覀冇玫臄?shù)據(jù)庫并不是在本地,如果是連本機(jī)前硫,可以直接使用localhost
        'PORT': 3306,   #配置數(shù)據(jù)庫的端口
    }
}

關(guān)于報錯問題

  • raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__) django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.

    • 解決辦法:找到Python安裝路勁下的Python36-32\Lib\site-packages\django\db\backends\mysql\base.py文件胞得,將文件中的如下代碼注釋`
if version < (1, 3, 3):
    raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
  • 注釋后,筆者又遇到了一個報錯:query = query.decode(errors='replace')

    • 解決辦法:更進(jìn)一步修改 operations.py屹电。把其中的query = query.decode(errors='replace')修改為query = query.encode(errors='replace')
  • 其他報錯:

    • SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xca in position 2: invalid conti nuation byte

      • 解決辦法:在報錯的文件第一行添加:# -*- coding:utf-8 -*-

重定向

這里說的重定向阶剑,就是當(dāng)一個視圖函數(shù)處理完請求后,繼續(xù)返回到某一頁面

代碼示例:

from datetime import date
from django.http import HttpResponseRedirect
def create(request):
    """新增一本圖書"""
    b = BookInfo()
    b.btitle = "流行蝴蝶劍"
    b.bpub_date = date(2000,11,12)
    b.save()
    # return HttpResponse('ok')
    # 返回應(yīng)答:讓瀏覽器再訪問/index/危号,這就需要用到:from django.http import HttpResponseRedirect
    return  HttpResponseRedirect(redirect_to='/index')
    # HttpResponseRedirect也有簡單的寫法:
    # from django.shortcuts import redirect
    # return redirect('index')

相應(yīng)html代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>圖書信息</title>
</head>
<body>
    <h1>圖書信息如下:</h1>
    <a href="/create">新增</a>
<!--    注意:這里的/create相當(dāng)于127.0.0.1:8000/create-->
<!-- 但是如果不加/,就是和之前的地址進(jìn)行拼接牧愁,比如,如果之前的地址是127.0.0.1:8000/index外莲,那么此時就是127.0.0.1:8000/index/create -->
    <ul>
        {% for book in books %}
            <li>{{ book.btitle }}---{{ book.bpub_date }}</li>
        {% empty %}
            <li>信息為空</li>
        {% endfor %}
    </ul>
</body>
</html>

當(dāng)我們點(diǎn)擊添加的時候猪半,本來會跳轉(zhuǎn)到127.0.0.1:8000/create,但是由于其視圖函數(shù)處理后進(jìn)行了重定向偷线,所以我們在瀏覽器就看不到這個跳轉(zhuǎn)的過程

在這里插入圖片描述

通過模型類查詢表中的數(shù)據(jù)

更改配置使其產(chǎn)生日志文件

在Linux里面讓mysql產(chǎn)生日志文件mysql.log

  • 使用sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf命令打開mysql的配置文件磨确,去除68,69行的注釋
  • sudo service mysql restart)重啟mysql服務(wù)声邦,就會產(chǎn)生mysql日志文件
  • 打開MySQL的日志文件乏奥。/var/log/mysql/mysql.log 是mysql日志文件所在的位置。
  • 如果使用sudo tail -f /var/log/mysql/mysql.log可以實(shí)時查看其中的日志文件

查詢函數(shù)

通過 模型類.objects屬性可以調(diào)用如下函數(shù)亥曹,實(shí)現(xiàn)對模型類對應(yīng)的數(shù)據(jù)表的查詢邓了,注意,要是模型類媳瞪,而不是它的實(shí)例

類名就相當(dāng)于(注意驶悟,不是)表的名字,模型類.xxx就是在表中查找數(shù)據(jù)

以下格式:(函數(shù)名:功能材失;返回值;說明)

  • get:返回表中滿足條件的一條且僅能有一條數(shù)據(jù)硫豆;返回值是一個模型類對象龙巨;參數(shù)中寫查詢條件,如果查詢到多條語句熊响,拋出異常MultipleObjectsReturned旨别,查詢不到語句,拋出DoesNotExist
  • all:返回模型類對應(yīng)表格中的所有數(shù)據(jù)汗茄;返回值是QuerySet類型秸弛;查詢集
  • filter:返回滿足條件的數(shù)據(jù);返回值是QuerySet類型;參數(shù)寫查詢條件
  • exclude:返回不滿足條件的數(shù)據(jù)递览;返回值是QuerySet類型叼屠;參數(shù)寫查詢條件
  • order_by:對查詢結(jié)果進(jìn)行排序;返回值是QuerSet類型绞铃;參數(shù)中寫根據(jù)哪字段進(jìn)行排序镜雨,eg:以id升序排列,參數(shù)就為'id'儿捧,如果以id降序荚坞,'-id'

查詢時使用的條件

條件的格式:模型類的屬性名__條件名=值\

在查詢時,可以傳多個條件菲盾,他們之間是且的關(guān)系

# 判等:exact
BookInfo.objects.get(id=1)  #完全的寫法為:BookInfo.objects.get(id__exact=1)

# 模糊查詢
# 包含:contains
BookInfo.objects.filter(btitle__contains='傳')   #查詢名字中含有“傳”字的書
# 以xxx結(jié)尾:endswith
# 以xxx開始:starswith

# 空查詢:isnull
BookInfo.objects.filter(btitle__isnull=False)   #查詢書名不為空的數(shù)據(jù)

# 范圍查詢:in
# eg:查詢id為1或3或5的圖書
BookInfo.objects.filter(id__in=[1,3,5])

# 比較查詢
# gt:great than,大于    lt:less than颓影,小于    gte:great euqal,大于等于    lte:less than equal懒鉴,小于等于
# eg:查詢編號大于3的圖書
BookInf.objects.filter(id__gt=3)

# 日期查詢
BookInfo.objects.filter(bpub_date__year=19990)  #date有一個屬性為year
from datetime import date
BookInfo.objects.filter(bpub_date__gt=date(1980,1,1))

對于QuerySet诡挂,可以直接繼續(xù)調(diào)用上面的方法

eg:把id大于3的圖書信息按閱讀量從大到小排序顯示:BookInfo.objects.filter(id__gt=3).order_by('-bread'),因?yàn)閒ilter返回的是一個QuerySet疗我,所以可以直接繼續(xù)調(diào)用order_by

Q對象

作用:用于查詢時條件之間的邏輯關(guān)系:not and or 咆畏,可以對Q對象進(jìn)行& | -操作,~取反

使用之前需要先導(dǎo)入:from django.db.models import Q

eg:

BookInfo.objects.fitler(Q(id=1) | Q(id=2))
BookInfo.objects.fitler(Q(id=1) | Q(id=2))

F對象

作用:用于類屬性之間的比較

使用之前需要先導(dǎo)入:from django.db.models import F

eg:查詢圖書閱讀量大于評論量

BookInfo.objects.filter(bread__gt=F('bcomment'))

# F對象還可以進(jìn)行算數(shù)的運(yùn)算
# 查詢圖書閱讀量大于兩倍評論量的信息
BookInfo.objects.filter(bread__gt=2F('bcomment')*2)

聚合函數(shù)

作用:對查詢結(jié)果進(jìn)行聚合操作

sum count avg max min

aggregate:調(diào)用這個函數(shù)來使用聚合吴裤。返回值是一個字典

使用之間需要先導(dǎo)入聚合類:from django.db.models import Sum,Count,Max,Min,Avg

案例:

# 查詢所有圖書的數(shù)目
from django.db.models import Count,Sum
BookInfo.objects.all().aggregate(Count('id'))
# 注意:count的參數(shù)不能為*

# 查詢所有圖書閱讀量的總和
BookInfo.objects.aggregate(Sum('bread'))

count函數(shù)旧找,注意,這里說的不是上面的Count

返回值是一個數(shù)

eg:查詢所有圖書的數(shù)目

BookInfo.objects.all().count()
# 同樣的麦牺,如果是對一個表中的所有數(shù)據(jù)進(jìn)行查詢钮蛛,.all()都可以省略
# 即:可以寫成:BookInfo.objects.count()

查詢集

all filter exclude order_by 調(diào)用這些函數(shù)會產(chǎn)生一個查詢集

查詢集特性

  • 惰性查詢:只有在實(shí)際使用查詢集中的數(shù)據(jù)的時候才會發(fā)生對數(shù)據(jù)庫的真正查詢,eg:當(dāng)book = BookInfo.objects.all()的時候剖膳,不會產(chǎn)生數(shù)據(jù)的查詢
  • 緩存:當(dāng)使用的是同一個查詢集時魏颓,第一次的時候會發(fā)生數(shù)據(jù)庫的查詢,然后把結(jié)果緩存起來吱晒,之后再使用這個查詢集時甸饱,使用的是緩存中的結(jié)果

限制查詢集

可以對一個查詢集進(jìn)行 取下標(biāo)或者切片 操作來限制查詢集的結(jié)果

對一個查詢集進(jìn)行切片操作會產(chǎn)生一個新的查詢集,下標(biāo)不允許為負(fù)

eg:

books = BookInfo.objects.all()
bk2 = books[0:3]

取出查詢集第一條數(shù)據(jù)的兩種方式:

  • b[0]:如果不存在仑濒,會拋出IndexError異常
  • b[0:1].get():如果不存在叹话,會拋出DoesNotExist異常

exists:判斷一個查詢集中是否有數(shù)據(jù),返回結(jié)果為True或False

用法:查詢集.exists()

模型類之間的關(guān)系

和表一樣墩瞳,模型類之間也有三種關(guān)系

一對多關(guān)系

例:圖書類-英雄類

models.ForeignKey() 定義在多的類中

多對多關(guān)系

例:新聞類-新聞類型類驼壶,一篇新聞可能是體育新聞,還可能是國際新聞喉酌,同樣热凹,體育新聞下也有多篇新聞

models.ManyToManyField() 定義在哪個類中都可以

一對一關(guān)系

例:員工基本信息類-員工詳細(xì)信息類

models.OneToOneField 定義在哪個類中都可以

關(guān)聯(lián)查詢(一對多)

我們把在“多”的類中定義的屬性叫做關(guān)聯(lián)屬性

案例:

# 查詢圖書id為1的圖書關(guān)聯(lián)的所有英雄的信息
b = BookInfo.objects.get(id=1)
b.heroinfo_set.all()

# 查詢id為1的英雄關(guān)聯(lián)的圖書信息
h = HeroInfo.objects.get(id=1)
h.hbook()

在這里插入圖片描述

通過模型類實(shí)現(xiàn)關(guān)聯(lián)查詢

例:查詢圖書信息泵喘,要求圖書管理的英雄的描述包含“八”

Book.Info.objects.filter(heroinfo__hcoment__contains=8)

heroinfo是對應(yīng)的“多”的類名的小寫,hcomment是“多”的屬性(相當(dāng)于表中的字段)般妙,contains是條件表達(dá)式

最終要拿到哪個表中的數(shù)據(jù)纪铺,就通過哪個表來查

例:查詢圖書信息,要求圖書中的英雄的id大于3

BookInfo.objects.filter(heroinfo__id__gt=3)

例:查詢書名為“天龍八部”的所有英雄

Hero.objects.filter(hbook__bititle="天龍八部“)

注意:如果前面要查詢的類中沒有該關(guān)系屬性股冗,后面的參數(shù)中就必須寫類名霹陡;如果前面類中有該關(guān)系屬性,寫的應(yīng)該是屬性名

插入止状、更新和刪除

調(diào)用一個模型類對象的save方法的時候就可以實(shí)現(xiàn)對模型類對應(yīng)數(shù)據(jù)表的插入和更新

調(diào)用一個模型類對象的delete方法的時候烹棉,就可以實(shí)現(xiàn)對模型類對應(yīng)數(shù)據(jù)的刪除

自關(guān)聯(lián)

自關(guān)聯(lián)是一種特殊的一對多的關(guān)系,只是這些一對多的關(guān)系都在一張表里面

示例:

class AreaInfo(models.Model):
    """地區(qū)模型類"""
    atitle = models.CharField(max_length=20)
    # 關(guān)系屬性怯疤,代表當(dāng)前地區(qū)的父級地區(qū)
    aParent = models.ForeignKey('self', null=True, blank=True,on_delete=models.CASCADE)   #代表這個類與他自身有了這種關(guān)聯(lián)

管理器

BookInfo.objects.all() --> objects到底是一個什么東西浆洗?

答:objects是django幫助我們自動生成的管理器對象,通過這個管理器可以實(shí)現(xiàn)對數(shù)據(jù)的查詢

objects是models.Manager類的一個對象集峦。自定義管理器后Django不再幫助我們生成默認(rèn)的objects管理器

示例:

class BookInfo(models.Model):
    """圖書模型類"""
    btitle = models.CharField(max_length=20)
    bpub_date = models.DateField()
    bread = models.IntegerField(default=0)
    bcomment = models.IntegerField(default=0)
    isDelete = models.BooleanField(default=False)   #刪除的時候伏社,執(zhí)行邏輯刪除,而非真正的刪除塔淤,默認(rèn)不刪除
    book = models.Manager()     #自定義一個管理器對象

此時摘昌,我們就不能夠通過BookInfo.objects.xxx來查詢數(shù)據(jù),而是使用:BookInfo.book.xxx

在這里插入圖片描述

通常高蜂,我們是自己定義一個類聪黎,繼承models.Manager類,然后讓其作為管理器類

自定義管理器類的作用:

  • 通過對方法的重寫备恤,改變查詢的結(jié)果集

代碼示例:不返回邏輯上被刪除了的數(shù)據(jù)

class BookInfoManager(models.Manager):
    def all(self):
        # 1. 調(diào)用父類的all方法獲取所有數(shù)據(jù)
        books = super().all()
        books.filter(isDelete=False)
        return books
  • 添加額外的方法以簡化操作

代碼示例:

class BookInfoManager(models.Manager):
    def all(self):
        # 1. 調(diào)用父類的all方法獲取所有數(shù)據(jù)
        books = super().all()
        books.filter(isDelete=False)
        return books
    # 2. 封裝函數(shù):操作模型類對應(yīng)的數(shù)據(jù)表(增刪查改)

    def create_book(self, btitle, bpub_date):
        obj = BookInfo()
        obj.btitle = btitle
        obj.bpub_date = bpub_date
        obj.save()
        return obj

效果:


在這里插入圖片描述

注意:在models.Manager里面默認(rèn)給我們封裝好了一個create方法稿饰,不過必須要通過關(guān)鍵字傳參

以上代碼還有 一個問題:即,一旦模型類的名字發(fā)生改變露泊,我們就必須手動更改管理器內(nèi)的代碼喉镰,我們可以通過self.model來獲得模型類的名稱

代碼示例:

class BookInfoManager(models.Manager):
    def all(self):
        # 1. 調(diào)用父類的all方法獲取所有數(shù)據(jù)
        books = super().all()
        books.filter(isDelete=False)
        return books
    # 2. 封裝函數(shù):操作模型類對應(yīng)的數(shù)據(jù)表(增刪查改)

    def create_book(self, btitle, bpub_date):
        model_class = sel.model #獲得model所在的模型類
        obj = model_class() #創(chuàng)建對象
        obj.btitle = btitle
        obj.bpub_date = bpub_date
        obj.save()
        return obj

模型管理器類和模型類的關(guān)系

在這里插入圖片描述

元選項(xiàng)

情景:由于我們生成的表的名字為”應(yīng)用名_小寫的模型類名",那么當(dāng)我們的應(yīng)用名一旦發(fā)生改變惭笑,該模型類對應(yīng)的表名就跟著改變侣姆,但是這個類對應(yīng)的表名已經(jīng)生成了,這就會導(dǎo)致無法訪問原表沉噩,會報錯

如何解決:讓模型類對應(yīng)的表名不依賴于應(yīng)用的名字:通過元選項(xiàng)指定表名铺敌,在模型類里面定義一個元類,通過該類里面的db_table屬性來定義表名

代碼示例:

class BookInfo(models.Model):
    """圖書模型類"""
    btitle = models.CharField(max_length=20)
    bpub_date = models.DateField()
    bread = models.IntegerField(default=0)
    bcomment = models.IntegerField(default=0)
    isDelete = models.BooleanField(default=False)   #刪除的時候屁擅,執(zhí)行邏輯刪除,而非真正的刪除产弹,默認(rèn)不刪除
    objects = BookInfoManager()     #自定義一個管理器對象
    class Meta:
        db_table = "bookinfo"   # 指定模型類對應(yīng)的表名為bookinfo

如果僅僅是要建立與表的對應(yīng)關(guān)系(模型類中的名字與鮮美 存表中的名字不一致)派歌,直接這樣即可弯囊;如果我們是要用此法更改名字,需要我們再重新做一下遷移

視圖(V)

視圖的功能:接收請求胶果,進(jìn)行處理匾嘱,與M和T進(jìn)行交互,返回應(yīng)答

返回html內(nèi)容HttpResponse早抠,一可能重定向redirect

視圖函數(shù)的使用

使用

使用

  • 定義視圖函數(shù)

    • request參數(shù)必須有霎烙。是一個HttpRequest對象,參數(shù)名可以變化蕊连,但不要更改
  • 配置url:建立url與視圖函數(shù)之間的對應(yīng)關(guān)系

url配置過程

  • 在項(xiàng)目的urls文件中包含具體應(yīng)用的urls文件悬垃,在具體應(yīng)用的urls文件中寫url和視圖的對應(yīng)關(guān)系
  • url配置項(xiàng)是定義在一個叫做urlpatterns的列表中,其中的每一個元素就是一個配置項(xiàng)甘苍,每一個配置項(xiàng)都調(diào)用url函數(shù)(現(xiàn)在已經(jīng)是調(diào)用path函數(shù)了尝蠕,不過url函數(shù)仍然可以)

匹配過程

在這里插入圖片描述
  1. 去除域名和后面的參數(shù),剩下/aindex,再把前面的/去掉载庭,剩下aindex
  2. 拿aindex先到項(xiàng)目的url.py文件中進(jìn)行從上到下的匹配看彼,匹配成功之后執(zhí)行后面對應(yīng)的處理動作,就是把匹配成功的部分a字符去除囚聚,然后拿剩下的部分index到應(yīng)用的urls.py文件中再進(jìn)行從上到下的匹配靖榕。
  3. 如果匹配成功則調(diào)用相應(yīng)的視圖產(chǎn)生內(nèi)容返回給客戶端。如果匹配失敗則產(chǎn)生404錯誤顽铸。

錯誤視圖

當(dāng)我們訪問一個不存在的頁面時茁计,會看到一個如下的錯誤信息


在這里插入圖片描述

這通常是為了調(diào)試方便,會將我們網(wǎng)站的地址配置顯示出來跋破,小實(shí)際應(yīng)用中是不可取的簸淀,根據(jù)紅色框內(nèi)的提示信息,我們可以通過更改配置來顯示標(biāo)準(zhǔn)的404頁面

  • 找到項(xiàng)目的settings文件
  • 更改DEBUG=FALSE # 關(guān)閉debug模式
  • 更改ALLOWED_HOSTS=['*'] #表示允許所有ip訪問
  • 如果要顯示自定義的頁面毒返,則需要的templates目錄下面自定義一個404.html文件租幕。注意,這個文件不需要我們自己配置拧簸,django會自動調(diào)用劲绪,同時會向該文件傳一個名為request_path的模板變量,表示用戶請求的頁面

404錯誤通常源于:

  • url沒有配置
  • url配置錯誤

如果是自己的視圖里面出錯盆赤,在瀏覽器端會提示500錯誤贾富,如果我們不想使用默認(rèn)的,也可以自己在templates下面自定義一個名為500的html

通常牺六,我們在開發(fā)過程中颤枪,要打開DEBUG模式

捕獲url參數(shù)

進(jìn)行url匹配時,把所需要的捕獲的部分設(shè)置成一個正則表達(dá)式組淑际,這樣django框架就會自動把匹配成功后相應(yīng)組的內(nèi)容作為參數(shù)傳遞給視圖函數(shù)畏纲。一旦進(jìn)行了捕獲扇住,在視圖函數(shù)中就必須聲明。

  • 位置參數(shù)盗胀,直接在正則表達(dá)式中分組即可艘蹋,參數(shù)名可以隨便指定
  • 關(guān)鍵字參數(shù):在位置參數(shù)的基礎(chǔ)上給正則表達(dá)式組命名即可。(?P<組名>正則表達(dá)式)票灰,關(guān)鍵字參數(shù)中女阀,視圖中參數(shù)名必須和正則表達(dá)式組名一致

視圖函數(shù)中的request參數(shù)

request就是HttpRequest類型的對象,其中包含著瀏覽器請求的一些信息屑迂,就是把WSGI模型中的application函數(shù)中的env進(jìn)行了一層包裝

案例:模擬登錄

先在settings文件中注釋掉'django.middleware.csrf.CsrfViewMiddleware',浸策,否則會出現(xiàn)403錯誤。也可以from django.views.decorators.csrf import csrf_exempt屈糊,然后用csrf_exempt裝飾對應(yīng)的視圖函數(shù)

應(yīng)用urls配置文件:

from booktest import views
from django.urls import path
urlpatterns = [
    path(r'index', views.index),
    path(r'login', views.login),
    path(r'login_check',views.login_check)
]

將應(yīng)用urls包含到項(xiàng)目urls文件中的代碼:略

views文件代碼:

# -*- coding:utf-8 -*-
from django.shortcuts import render,redirect
# Create your views here.
from datetime import date
from django.http import HttpResponse, HttpResponseRedirect

def index(request):
    return HttpResponse("hello world")
    
def login(request):
    return render(request,'booktest/login.html',{})

def login_check(request):
    # 1. 獲取提交的用戶名和密碼
    # 2. 進(jìn)行登錄的校驗(yàn)
    # 3. 返回應(yīng)答
    """
    request對象有兩個屬性:他們的是QueryDict類型的對象的榛,和字典很相似,可以通過鍵取出值
    request.POST:保存的是post的提交參數(shù)
    request.GET:保存的是get方式提交的參數(shù)
    QueryDict的用法:
        from django.http.request import QueryDict
        q = QueryDict('a=1&b=2&c=3')    #實(shí)例化了一個QueryDict對象逻锐,他里面存儲了abc三個屬性
        q['a']  #就能夠獲得a的值1夫晌,還可以通過q.get('a")獲得
        # 同字典一樣,如果是用中括號取昧诱,如果鍵不存在晓淀,會拋異常,如果是get方法取盏档,鍵不存在會返回none凶掰,不會報錯
        # get方法也可以默認(rèn)值

        #QueryDict和字典的本質(zhì)區(qū)別
            #在字典中,一個鍵只能對應(yīng)一個值蜈亩,而QueryDict一個鍵可以對應(yīng)多個值
            #eg:
            q1 = QueryDict('a=1&a=2&a=3&b=4')
            q1['a'] #返回3
            q1.get('a') #返回3
            q1.getlist('a') #返回一個列表懦窘,其中元素為1、2稚配、3
    """
    username = request.POST.get('username')    #post提交的數(shù)據(jù)中畅涂,鍵就是表單的name值
    password = request.POST.get('password')
    #實(shí)際情況下,用戶名和密碼應(yīng)該是到數(shù)據(jù)庫中去查找
    #模擬:用戶名為smart道川,密碼為123
    if username=="smart" and password == "123":
        #正常情況下午衰,我們登錄成功后,會跳轉(zhuǎn)到一個頁面冒萄,這里我們跳轉(zhuǎn)到首頁
        return redirect('/index')
    else:
        #用戶和密碼錯誤就還是跳轉(zhuǎn)到登錄頁面
        return redirect('/login')

login.html代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登錄</title>
</head>
<body>
<!--表單的兩種提交方式:-->
<!--1. POST:提交的參數(shù)在請求頭里面臊岸,如果數(shù)據(jù)比較重要,采用POST-->
<!--2.GET:提交的參數(shù)在url中-->
<form method="post" action="/login_check">
<!--    表單中的action就指定我們提交的地址-->
<!--    method指定表單提交的方式-->
    用戶名:<input type="text", name="username"><br>
    密碼:<input type="password", name="password"><br>
    <input type="submit", value="登錄">
</form>
</body>
</html>

注意:此種方式中尊流,我們采用的是全局刷新如果登錄頁面內(nèi)容過多帅戒,產(chǎn)生的體驗(yàn)相當(dāng)不好,此問題可以結(jié)合ajax采用局部刷新

ajax實(shí)現(xiàn)局部刷新的流程:


在這里插入圖片描述

注意:后臺返回的數(shù)據(jù)就在function的data里面

ps:css崖技、js逻住、images等靜態(tài)文件施流,在django中,都要放在項(xiàng)目下的static文件夾中鄙信,然后到settings中進(jìn)行配置,如下:

#在最后一行:
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static')]    #設(shè)置靜態(tài)文件的保存目錄

通常忿晕,每種靜態(tài)文件都放在一個文件夾下面装诡,eg:js就放在js文件夾下面,css践盼、images類似

ajax請求

在項(xiàng)目文件夾下的static/js下鸦采,有jquery文件

ajax就是異步的javascript,其異步體現(xiàn)在咕幻,當(dāng)發(fā)起了ajax請求之后渔伯,不等待回調(diào)函數(shù)的執(zhí)行,而是繼續(xù)往下執(zhí)行代碼

當(dāng)然肄程,也可以發(fā)起同步的ajax請求锣吼,只需添加:'async':false即可

注意:ajax的請求都是在后臺

test_ajax.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax</title>
    <script src="/static/js/jquery-3.4.1.js"></script>
    <script>
        $(function(){
            $('#btnAjax').click(function(){ //當(dāng)點(diǎn)擊該按鈕的時候,發(fā)起ajax請求
                $.ajax({
                    'url':'/ajax_handle',
                    'type':'get',
                 // type不寫的話默認(rèn)就是get
                    'dataType':'json'
                }).done(function(data){
                    //進(jìn)行處理
                    alert(data.res)
                })
            })
        })
    </script>
</head>
<body>
<input type="button" value="ajax請求" id="btnAjax">
<!--一點(diǎn)擊按鈕的時候蓝厌,就發(fā)起一個ajax的請求-->
</body>
</html>

應(yīng)用下的urls文件

from booktest import views
from django.urls import path
urlpatterns = [
    path(r'index', views.index),
    # path(r'create', views.create),  #新增一本圖書
    # path(r'areas',views.areas),
    path(r'login', views.login),
    path(r'login_check',views.login_check),
    path(r'test_ajax',views.ajax_test), #顯示ajax頁面
    path(r'ajax_handle',views.ajax_handle),
]

應(yīng)用下的views.py

from django.shortcuts import render,redirect
def ajax_test(request):
    return render(request,'booktest/test_ajax.html')

from django.http import HttpResponse, JsonResponse
def ajax_handle(request):
    # 注意:是return 一個JsonResponse的對象
    # 假設(shè)返回的是{'res':1}
    return JsonResponse({'res':1})

效果圖:


在這里插入圖片描述

同時玄叠,如果我們用瀏覽器,查看“網(wǎng)絡(luò)”拓提,會發(fā)現(xiàn)它并沒有請求整個頁面读恃,即:實(shí)現(xiàn)了局部刷新

在使用ajax實(shí)現(xiàn)局部刷新時,我們首先要分析出訪問地址時需要攜帶的參數(shù)以及視圖函數(shù)處理完成之后代态,所返回的json格式

HttpRequest對象講解

屬性

  • 下面除非特別說明寺惫,屬性都是只讀的。
  • path:一個字符串蹦疑,表示請求的頁面的完整路徑西雀,不包含域名和參數(shù)部分。
  • method:一個字符串必尼,表示請求使用的HTTP方法蒋搜,常用值包括:'GET'、'POST'判莉。
    • 在瀏覽器中給出地址發(fā)出請求采用get方式豆挽,如超鏈接。
    • 在瀏覽器中點(diǎn)擊表單的提交按鈕發(fā)起請求券盅,如果表單的method設(shè)置為post則為post請求帮哈。
  • encoding:一個字符串,表示提交的數(shù)據(jù)的編碼方式锰镀。如果為None則表示使用瀏覽器的默認(rèn)設(shè)置娘侍,一般為utf-8咖刃。這個屬性是可寫的,可以通過修改它來修改訪問表單數(shù)據(jù)使用的編碼,接下來對屬性的任何訪問將使用新的encoding值。
  • GET:QueryDict類型對象对碌,類似于字典欣福,包含get請求方式的所有參數(shù)。
  • POST:QueryDict類型對象,類似于字典,包含post請求方式的所有參數(shù)。
  • FILES:一個類似于字典的對象箩帚,包含所有的上傳文件。
  • COOKIES:一個標(biāo)準(zhǔn)的Python字典黄痪,包含所有的cookie紧帕,鍵和值都為字符串。
  • session:一個既可讀又可寫的類似于字典的對象桅打,表示當(dāng)前的會話是嗜,只有當(dāng)Django 啟用會話的支持時才可用,詳細(xì)內(nèi)容見"狀態(tài)保持"油额。

狀態(tài)保持

http協(xié)議是無狀態(tài)的叠纷,下一次去訪問一個頁面時,并不知道上一次對這個頁面做了什么

cookie

cookie是由服務(wù)器生成潦嘶,保存在瀏覽器端的一小段文本信息

cookie的特點(diǎn):

  1. 以鍵值對方式進(jìn)行存儲涩嚣。
  2. 通過瀏覽器訪問一個網(wǎng)站時,會將瀏覽器存儲的跟網(wǎng)站相關(guān)的所有cookie信息發(fā)送給該網(wǎng)站的服務(wù)器掂僵。request.COOKIES
  3. cookie是基于域名安全的航厚。www.baidu.com www.tudou.com
  4. cookie是有過期時間的,如果不指定锰蓬,默認(rèn)關(guān)閉瀏覽器之后cookie就會過期幔睬。

設(shè)置cookie:需要一個HttpRespose類的對象,或者是它的子類對象芹扭,通過它的set_cookie方法麻顶,我們可以設(shè)置cookie

瀏覽器發(fā)給服務(wù)器的cookie保存在request對象的COOKIES里面,它是一個標(biāo)準(zhǔn)的字典

HttpResponse有哪些子類舱卡?答:HttpResponseRedirect以及JsonResponse都是

代碼示例:

from datetime import datetime,timedelta
from django.http import HttpResponse, HttpResponseRedirect
def set_cookie(request):
    response = HttpResponse('set_cookie')
    # 設(shè)置一個cookie信息
    response.set_cookie('num',1, expires=datetime.now()+timedelta(days=14))    
    #第一個參數(shù)就是"鍵",第二個參數(shù)就是"值"辅肾;后面是指定過期時間為14天
    #指定過期時間也可以使用max_age,單位為s,但是可以直接寫計算式
    response.set_cookie('num2',2, expires=datetime.now()+timedelta(days=14))    #可以設(shè)置多個cookie
    return response
    # 當(dāng)我們return一個response的時候轮锥,這個cookie會交給瀏覽器保存

def get_cookie(request):
    num = request.COOKIES['num']
    return HttpResponse(num)

除了以上代碼外矫钓,只需要配置urls文件即可

session

session與cookie最大的區(qū)別是cookie保存在瀏覽器端而session保存在服務(wù)器端

對于敏感、重要的信息,建議要儲在服務(wù)器端新娜,不能存儲在瀏覽器中赵辕,如用戶名、余額概龄、等級还惠、驗(yàn)證碼等信息。

在這里插入圖片描述

session的特點(diǎn)

  1. session是以鍵值對進(jìn)行存儲的私杜。
  2. session依賴于cookie吸重。唯一的標(biāo)識碼保存在sessionid cookie中。
  3. session也是有過期時間歪今,如果不指定,默認(rèn)兩周就會過期颜矿。

在用django創(chuàng)建的mysql數(shù)據(jù)庫中寄猩,有一張django_session表,專門用來存儲session

代碼示例:

def get_cookie(request):
    num = request.COOKIES['num']
    return HttpResponse(num)

from django.http import HttpResponse
def set_session(request):
    request.session['username'] = 'smart'
    request.session['password'] =  '123'
    return HttpResponse('設(shè)置session')

def get_session(request):
    username = request.session['username']
    password = request.session['password']
    return HttpResponse(username+":"+password)

除此之外骑疆,只需要設(shè)置urls即可

效果圖:數(shù)據(jù)是經(jīng)過base64編碼的

在這里插入圖片描述
瀏覽器端查看:
在這里插入圖片描述

session的其他方法

  • 取值:request.session.get('key', defaultValue)
  • 清楚所有session:request.session.clear()田篇,在存儲中刪除值的部分,但是該條記錄還在
  • 刪除整條數(shù)據(jù):request.session.flush箍铭,刪除后泊柬,該條記錄都已經(jīng)不存在
  • 刪除session中的指定鍵及值,在存儲中只刪除某個鍵及對應(yīng)值:del request.session.['key']
  • 設(shè)置會話的超時時間诈火,如果沒有指定過期時間兽赁,則默認(rèn)是兩個星期:request.session.set_expiry(value),是設(shè)置sessionid這個cookie的冷守,整數(shù)刀崖,單位為s,即:刪除后拍摇,瀏覽器端的sessionid將過期亮钦,就無法通過sessionid去服務(wù)器端獲取其對應(yīng)值
  • 判斷session中是否存在某key:request.session.has_key['key']

模板(T)

模板的功能

產(chǎn)生html頁面,控制頁面上展示的內(nèi)容充活,模板文件不僅僅是一個html文件蜂莉。

模板文件包含兩個部分的內(nèi)容:

  • 靜態(tài)內(nèi)容:css、js混卵、html
  • 動態(tài)內(nèi)容:用于動態(tài)去產(chǎn)生一些網(wǎng)頁內(nèi)容映穗,通過模板語言來產(chǎn)生

模板文件的加載順序

  • 首先去配置的模板目錄下面去找模板文件,由于該配置項(xiàng)是一個列表淮菠,所以我們也可以添加多個男公,查找的時候從前往后查找。
  • 去INSTALLED_APPS下面的每個應(yīng)用的templates去找模板文件,前提是應(yīng)用中必須有templates文件夾枢赔。

模板語言

模板文件中的動態(tài)內(nèi)容即由模板語言產(chǎn)生

模板變量

模板變量名是由數(shù)字澄阳,字母,下劃線和點(diǎn)組成的踏拜,不能以下劃線開頭碎赢。

使用模板變量:{{模板變量名}},如果是在{%%}的代碼區(qū)速梗,可以直接使用

模板變量的解析順序:例如:{{ book.btitle }}

  • 首先把book當(dāng)成一個字典肮塞,把btitle當(dāng)成名,進(jìn)行取值book['btitle']
  • 把book當(dāng)成一個對象姻锁,把btitle當(dāng)成屬性枕赵,進(jìn)行取值book.btitle
  • 把book當(dāng)成一個對象,把btitle當(dāng)成對象的方法位隶,進(jìn)行取值book.btitle

例如:{{book.數(shù)字}}

  • 首先把book當(dāng)成一個字典拷窜,把0當(dāng)成名,進(jìn)行取值book[0]
  • 把book當(dāng)成一個列表涧黄,把0當(dāng)成下標(biāo)篮昧,進(jìn)行取值book[0]

如果解析失敗,不會報錯笋妥,而是用空字符串進(jìn)行替換

使用模板變量時懊昨,.前面的可能是一個字典,可能是一個對象春宣,還可能是一個列表酵颁。

模板標(biāo)簽

{% 代碼段 %}
    for循環(huán):
    {% for x in 列表 %}
    # 列表不為空時執(zhí)行
    {% empty %}
    # 列表為空時執(zhí)行
    {% endfor %}
可以通過{{ forloop.counter }}得到for循環(huán)遍歷到了第幾次。

{% if 條件 %}
{% elif 條件 %}
{% else %}
{% endif %}

關(guān)系比較操作符:> < >= <= == !=
注意:進(jìn)行比較操作時月帝,比較操作符兩邊必須有空格材义。

邏輯運(yùn)算:not and or

過濾器

過濾器用于對模板變量進(jìn)行操作。

過濾器的本質(zhì)是一個函數(shù)嫁赏,可能需要參數(shù)

使用格式:模板變量|過濾器:參數(shù)

常用過濾器:

  • date:改變?nèi)掌诘娘@示格式其掂。
  • length:求長度。字符串潦蝇,列表.
  • default:如果前面的計算結(jié)果為False款熬,則使用給定的默認(rèn)值,否則攘乒,使用原來的
    代碼示例:
{% for book in books %}
    {% if book.id <= 2 %}
        <li class = 'red'>{{ book.btitle }}---{{ book.bpub_date | date:'Y年-m月-d日' }}</li>
        <!-- Ymd是date函數(shù)的參數(shù)贤牛,Y表示以4位顯示年,m表示以兩位數(shù)字顯示月则酝,d... -->
    {% endif %}
{% endfor %}

個人對過濾器的理解殉簸,用過濾器過濾后的返回值替換原來的變量

更多相關(guān)內(nèi)容見官網(wǎng)

自定義過濾器

  • 在應(yīng)用下新建一個包,名為:templatetags,一個字母都不能錯
  • 然后在其里面新建一個py文件般卑,文件名隨意武鲁,我們的過濾器就寫在這里面
  • 過濾器的本質(zhì)就是python的函數(shù)

自定義過濾器的參數(shù)至少一個(前面的模板變量),最多兩個

代碼示例:

from django.template import Library

register = Library()    #創(chuàng)建一個Library對象

@register.filter    #用該對象中的filter裝飾自己定義的函數(shù)蝠检,使其成為一個過濾器
def mod(num):   #在使用過濾器的時候沐鼠,前面的部分就會作為第一個參數(shù)自動傳遞給過濾器,如果是需要多個參數(shù)叹谁,則使用方法如下:表達(dá)式或變量 | 過濾器:第二個參數(shù)(過濾器最多兩個參數(shù))
    return num % 2 == 0 #過濾掉奇數(shù)
  • 在要使用該過濾器的模板文件中的開始位置饲梭,對該過濾器進(jìn)行加載:{% load 自定義的過濾器的名字 %}

模板注釋

注意:模板注釋在瀏覽器上查看網(wǎng)頁源代碼的時候是無法看到的,但是html注釋的內(nèi)容是可以看到的

  • 單行注釋:{# 注釋內(nèi)容 #}

  • 多行注釋:

    {% comment %}
    注釋內(nèi)容
    {% endcomment %}

    模板繼承

    模板繼承也是為了重用html頁面內(nèi)容

    我們把每個頁面都一樣的內(nèi)容寫在父模板文件中

焰檩,至少一個(前面的模板變量)憔涉,最多兩個

代碼示例:

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}Base{% endblock title %}</title>
</head>
<body>
<h1>導(dǎo)航欄</h1>
{#頁面不同的地方,需要在父模板中預(yù)留位置析苫,這個位置我們稱為預(yù)留快#}
{#子模板就可以重寫父模板中預(yù)留塊的內(nèi)容#}
{% block block_name %}
父模板的預(yù)留塊中可以寫內(nèi)容监氢,也可以不寫,這里我們直接令預(yù)留塊的名字為block_name
{% endblock block_name %}
<h1>版權(quán)信息</h1>
</body>
</html>

child.html

{% extends 'booktest/base.html' %}
{#注意:路徑是相對于templates的#}
{#繼承了之后藤违,里面就不能再寫其他內(nèi)容#}

{#重寫父模板中的預(yù)留塊#}
{#如果不重寫預(yù)留塊中的內(nèi)容,就直接按照父模板中的內(nèi)容顯示#}

{% block block_name %}
{#    在子模板中纵揍,可以使用{{ block.super }}獲取父模板中預(yù)留塊的內(nèi)容#}
    {{ block.super }}<br>
    這是子模板中的內(nèi)容
{% endblock block_name %}

html轉(zhuǎn)義

在視圖函數(shù)中對模板傳參時(eg:render中)顿乒,會對以下字符自動轉(zhuǎn)義

小于號< 轉(zhuǎn)換為 &lt;

大于號> 轉(zhuǎn)換為 &gt;

單引號' 轉(zhuǎn)換為 &#39;

雙引號" 轉(zhuǎn)換為 &quot;

與符號& 轉(zhuǎn)換為 &amp;

如何關(guān)閉轉(zhuǎn)義:

法一:使用safe過濾器(不需要第二個參數(shù))

法二:使用autoescape標(biāo)簽,off表示關(guān)閉轉(zhuǎn)義泽谨,on表示打開轉(zhuǎn)義璧榄。用法如下:

{% autoescape off %}    
模板語言代碼
{% endautoescape %}

safe和autoescape的區(qū)別:safe是對一個變量起作用,而autoescape是對其內(nèi)部代碼段中的所有變量都關(guān)閉轉(zhuǎn)義

模板硬編碼中的字符串默認(rèn)不會經(jīng)過轉(zhuǎn)義

何為模板硬編碼中的字符串吧雹?即骨杂,寫“死”了的部分,示例如下:

{{ test | default:'<h1>hello</h1>' }}

其中雄卷,默認(rèn)的參數(shù)就不會被轉(zhuǎn)義

要對硬編碼進(jìn)行轉(zhuǎn)義搓蚪,必須手動執(zhí)行,eg:將<手動寫成&lt;

scrf攻擊

即:跨站請求的偽造

登錄裝飾器

情景示例

在進(jìn)行網(wǎng)站開發(fā)的時候丁鹉,有些頁面是用戶登錄后才能訪問的妒潭,假如用戶訪問了這個地址,需要進(jìn)行登錄的判斷揣钦,如果用戶登錄的話雳灾,可以進(jìn)行后續(xù)的操作,如果沒有登錄冯凹,跳轉(zhuǎn)到登錄頁谎亩。
我們就可以把這個登錄驗(yàn)證加在對應(yīng)頁面的視圖函數(shù)中
但是如果頁面過多,每個都要自己寫,就很麻煩匈庭,我們可以將其放在一個裝飾器里面

在這里插入圖片描述

csrf偽造

在這里插入圖片描述

上圖說明:

當(dāng)我們訪問正常網(wǎng)站時夫凸,一切正常,在我們的電腦上保存有sessionid嚎花,假設(shè)我們更改了在該網(wǎng)站的密碼(假設(shè)之后沒有退出寸痢,即瀏覽器一直保存有該sessionid);而當(dāng)我們訪問另一個網(wǎng)站時紊选,假設(shè)我們點(diǎn)擊了其上面的某按鈕或圖片時啼止,該網(wǎng)站向第一個網(wǎng)站發(fā)送了一個請求,該網(wǎng)站就能夠偽造我們的身份更改我們在第一個網(wǎng)站的密碼

csrf偽造成功的兩個關(guān)鍵點(diǎn):

  • 登錄正常網(wǎng)站之后兵罢,你的瀏覽器保存有sessionid献烦,且你沒有退出
  • 你不小心訪問了另外一個網(wǎng)站,并且你點(diǎn)擊了頁面上的按鈕

這即所謂的跨站請求偽造

Django默認(rèn)啟用了csfr防護(hù)卖词,即settings中的MIDDLEWARE_CLASSES中的django.middleware.csfr.CsrfViewMiddleware'項(xiàng)巩那。該防護(hù)只針對post提交。所以重要的數(shù)據(jù)用post提交

但是我們會發(fā)現(xiàn)打開之后此蜈,當(dāng)我們直接訪問/change_pwd后即横,訪問/change_pwd_action也會失敗(403)裆赵。此時东囚,就需要我們在post提交數(shù)據(jù)時加上{% csrf_token %}標(biāo)簽,eg战授,在表單提交post數(shù)據(jù)時页藻,在表單內(nèi)加上這個標(biāo)簽:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登錄</title>
</head>
<body>
<form method="post" action="/login_check">
    {% csrf_token %}
    用戶名:<input type="text", name="username" value={{username}}><br>
    密碼:<input type="password", name="password" value={{password}}><br>
    <input type="checkbox" name="remember">記住用戶名<br>
    <input type="submit", value="登錄">
</form>
</body>
</html>

防護(hù)的原理

  • 渲染模板文件時我們在模板中寫的{% csrf_token %}標(biāo)簽會被替換成一個名字叫做csrfmiddlewaretoken的隱藏域。
  • 服務(wù)器交給瀏覽器保存一個名字為csrftoken的cookie信息植兰。
  • 提交表單時份帐,兩個值都會發(fā)給服務(wù)器,服務(wù)器進(jìn)行比對楣导,如果一樣废境,則csrf驗(yàn)證通過,否則失敗筒繁。
  • 這種情況下彬坏,當(dāng)我們上方所說的另一個網(wǎng)站想訪問第一個時,由于它沒有該csrfmiddlewaretoken的隱藏域(因?yàn)椤傲硪粋€網(wǎng)站”是無法查看我們電腦本地的網(wǎng)頁源代碼的膝晾,也就拿不到該隱藏域)栓始,就會請求失敗,報403

驗(yàn)證碼

在用戶注冊血当、登錄頁面幻赚,為了防止暴力請求(不斷嘗試密碼)禀忆,可以加入驗(yàn)證碼功能,如果驗(yàn)證碼錯誤落恼,則不需要繼續(xù)處理箩退,可以減輕業(yè)務(wù)服務(wù)器、數(shù)據(jù)庫服務(wù)器的壓力佳谦。(只是因?yàn)槌绦蜃R別驗(yàn)證碼中的圖片的難度比較大戴涝,所以降低了暴力請求的概率,而不是絕對防止)

可以用Pillow這個包產(chǎn)生驗(yàn)證碼

from PIL import Image, ImageDraw, ImageFont
from django.utils.six import BytesIO
...
def verify_code(request):
    #引入隨機(jī)函數(shù)模塊
    import random
    #定義變量钻蔑,用于畫面的背景色啥刻、寬、高
    bgcolor = (random.randrange(20, 100), random.randrange(
        20, 100), 255)  #用rgb方式定義顏色
    width = 100
    height = 25
    #創(chuàng)建畫面對象咪笑,并設(shè)置寬高
    im = Image.new('RGB', (width, height), bgcolor)
    #創(chuàng)建畫筆對象
    draw = ImageDraw.Draw(im)
    #調(diào)用畫筆的point()函數(shù)繪制噪點(diǎn)
    for i in range(0, 100): #循環(huán)遍歷100次可帽,在畫面上添加噪點(diǎn)
        xy = (random.randrange(0, width), random.randrange(0, height))
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill=fill)   #指定在哪個點(diǎn)畫,畫的顏色是什么
    #定義驗(yàn)證碼的備選值
    str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
    #隨機(jī)選取4個值作為驗(yàn)證碼
    rand_str = ''
    for i in range(0, 4):
        rand_str += str1[random.randrange(0, len(str1))]
    #構(gòu)造字體對象窗怒,ubuntu的字體路徑為“/usr/share/fonts/truetype/freefont”
    font = ImageFont.truetype('FreeMono.ttf', 23)
    #構(gòu)造字體顏色
    fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
    #繪制4個字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
    #釋放畫筆
    del draw
    #存入session映跟,用于做進(jìn)一步驗(yàn)證(對比用戶輸入的驗(yàn)證碼對不對)
    request.session['verifycode'] = rand_str
    #內(nèi)存文件操作
    buf = BytesIO()
    #將圖片(im)保存在內(nèi)存中,文件類型為png
    im.save(buf, 'png')
    #將內(nèi)存中的圖片數(shù)據(jù)返回給客戶端扬虚,MIME類型為圖片png
    return HttpResponse(buf.getvalue(), 'image/png')

效果圖:

在這里插入圖片描述

注意:如果報OSError: cannot open resource錯誤努隙,通常是view中使用的字體不存在,如果是windows辜昵,直接采用Windows/Fonts下面存在的字體即可

校驗(yàn)用戶輸入的驗(yàn)證碼時荸镊,從session中取出正確值,再和用戶的輸入值相對比即可

url反向解析

比如路鹰,當(dāng)我們使用超鏈接在多個頁面間跳轉(zhuǎn)的時候,需要指呆跳轉(zhuǎn)到何處收厨,如果我們直接寫“死”了晋柱,當(dāng)頁面的地址發(fā)生變化時,我們就必須手動更改诵叁,非常麻煩雁竞。

這種情況下,我們沒有必要把它寫“死”拧额,可以在鏈接處動態(tài)獲取碑诉。

用法:

  1. 在項(xiàng)目的urls文件中進(jìn)行include時,指定namespace


    在這里插入圖片描述
  2. 在應(yīng)用的urls文件中配置url時侥锦,指定name
在這里插入圖片描述
  1. 在模板文件中使用該地址時进栽,格式如下:
  • {% url 'namespace名字:name' %} 例如{% url 'booktest:fan2'%}
  • 帶位置參數(shù)(通過url提交的參數(shù)):
    {% url 'namespace名字:name' 參數(shù)1 參數(shù)2 %} 例如{% url 'booktest:fan2' 1%},這里的參數(shù)在通過urls查找視圖函數(shù)的時候恭垦,會自動拼接成(/xxx)的形式快毛,然后傳遞給對應(yīng)的視圖函數(shù)
  • 帶關(guān)鍵字參數(shù)(通過url提交的參數(shù)格嗅,即,給組指定了名字):
    {% url 'namespace名字:name' 關(guān)鍵字參數(shù) %} 例如{% url 'booktest:fan2' id=1 %}

eg:

<a href="{{ url 'booktest:index'}}">首頁</a>
<!-- 其中唠帝,booktest是在項(xiàng)目urls文件中include時指定的namespace的名字屯掖,index是在應(yīng)用url中指定的name -->

在重定向的時候使用反向解析

from django.core.urlresolvers import reverse

重定向示例:

from django.core.urlresolvers import reverse
def test_redirect(request):
    url = reverse("booktest:index")
    # namespace:name
    # 如果有位置參數(shù):url = reverse('booktest:show_args",args=(1,2))    #將參數(shù)以元組的形式傳遞過去
    # 關(guān)鍵字參數(shù):url = reverse('booktest:show_kwargs',kwargs={c':3,'d':4}),則在調(diào)用對應(yīng)的視圖函數(shù)的時候,會以關(guān)鍵字的形式進(jìn)行傳參襟衰,傳遞給對應(yīng)的視圖函數(shù)
    return redirect(url)    #導(dǎo)入redirect的語句省略

其他技術(shù)

靜態(tài)文件

使用

在網(wǎng)頁使用的css文件贴铜,js文件和圖片叫做靜態(tài)文件

  • 在項(xiàng)目中新建文件夾static,通常瀑晒,每一個類別的文件都新建一個文件夾來保存
    在這里插入圖片描述
    - 在項(xiàng)目的settings.py中配置靜態(tài)文件所在的物理目錄绍坝,注意:其中STATIC_URL的所有是設(shè)置訪問靜態(tài)文件對應(yīng)的url地址,即:當(dāng)我們訪問的地址是以該值開頭的url時瑰妄,就會認(rèn)為其是一個靜態(tài)文件陷嘴,然后去項(xiàng)目的static文件夾下查找。比如间坐,我們將其改為了abc灾挨,那么在使用時,url就為'/abc/images/xxx'竹宋,而我們的所有靜態(tài)文件還是在項(xiàng)目的static文件夾下存儲
    在這里插入圖片描述
    - 在模板文件(html)中使用static文件夾下的文件時劳澄,路徑直接從static寫起,eg:<img src = '/static/images/mm.jpg'

如何在模板文件(html)中動態(tài)獲取STATIC_URL?

示例:

<!DOCTYPE html>
{% load staticfiles %} }
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板文件</title>
</head>
<body>
    <img src="{% static 'images/mm.jpg' %}">
{#    完成staticurl和路徑的拼接#}
{#    static就對應(yīng)這staticurl的配置#}
</body>
</html>

中間件

中間件函數(shù)是django框架給我們預(yù)留的函數(shù)接口蜈七,讓我們可以干預(yù)請求和應(yīng)答的過程秒拔。這個函數(shù)的名字和參數(shù)都已經(jīng)固定好了,必須按照規(guī)定的格式寫

eg:阻止某ip訪問自己的網(wǎng)站

獲取瀏覽器端的ip地址

使用request對象的META屬性:request.META.['REMOTE_ADDR']

阻止某ip訪問本網(wǎng)站的所有頁面的方法一

利用裝飾器飒硅,當(dāng)發(fā)現(xiàn)請求的ip是某個我們想阻止的ip時砂缩,進(jìn)行另外的處理

阻止某ip訪問本網(wǎng)站的所有頁面的方法二

  • 在應(yīng)用下新建一個py文件,名字可以變三娩,但是我們通常叫做middleware

  • 在里面定義process_view函數(shù)庵芭,注意,名字是固定的雀监,在視圖函數(shù)調(diào)用之前双吆,會先調(diào)用此函數(shù)。其參數(shù)為request, view_func,*views_args, **view_kwargs)会前。這個函數(shù)需要放到一個類里面

    • request:和視圖的request一樣
    • view_func:要調(diào)用的視圖函數(shù)
    • view_args好乐、*view_kwargs:視圖函數(shù)的位置參數(shù)和關(guān)鍵字參數(shù)

代碼示例(middleware.py):

from django.http import HttpResponse
class BolckedIPSMiddleware(object):
    # 中間件類
    EXCLUDE_IPS = ['192.168.14.74']
    def process_view(self,request, view_func, *view_args, **view_kwargs):
        # 中間件函數(shù)
        user_ip = request.META['REMOTE_ADDR']
        if user_ip in BolckedIPSMiddleware.EXCLUDE_IPS:
            return HttpResponse('forbidden')
  • 在項(xiàng)目的settings下 的MIDDLEWARE中對該我們自己定義的中間件類進(jìn)行注冊,eg:


    在這里插入圖片描述

詳解

中間件類的名字可以自己韧咭恕(常以MIDDLECLASS)結(jié)尾蔚万,但是里面的中間件函數(shù)名稱是固定的

常用中間件預(yù)留函數(shù): 名字和參數(shù)都是固定的

  • __init__:服務(wù)器重啟之后,響應(yīng)第一個請求的時候調(diào)用临庇。
  • process_request:是在產(chǎn)生request對象笛坦,進(jìn)行url匹配之前調(diào)用区转。必須有一個request參數(shù),即圖中的request對象
  • process_view:是url匹配之后版扩,調(diào)用視圖函數(shù)之前废离。參數(shù)為request, view_func, *view_args, **view_kwargs。分別為request對象礁芦、接下來要調(diào)用的視圖函數(shù)的 名字 蜻韭、視圖函數(shù)所需要用到的位置參數(shù)和關(guān)鍵字參數(shù)
  • process_response:視圖函數(shù)調(diào)用之后,內(nèi)容返回給瀏覽器之前柿扣。必須有request和response參數(shù)肖方,分別為request對象是視圖函數(shù)的返回值
  • process_exception:視圖函數(shù)出現(xiàn)異常,會調(diào)用這個函數(shù)未状。參數(shù)為request和exception俯画。分別為request對象和異常對象
  • 如果注冊的多個中間件類中包含process_exception函數(shù)的時候,調(diào)用的順序跟注冊的順序是相反的司草。

在類中艰垂,只定義需要用到的即可,不必全部定義

中間件函數(shù)的執(zhí)行流程: 其中的紅色箭頭部分表示人為的干預(yù)埋虹,讓其提前返回

在這里插入圖片描述


以下部分待改

上傳圖片

配置上傳文件保存目錄

需要先創(chuàng)建一個目錄猜憎,配置說明上傳文件就保存在該目錄下方
示例:
新建目錄:(目錄的位置和名字不固定)


在這里插入圖片描述

在項(xiàng)目settings中配置目錄:


在這里插入圖片描述

通過后臺管理頁面上傳

以圖片為例:

  1. 設(shè)計模型類
class PicClass(models.Model):
    gpic = models.ImageField(upload_to = "booktest")    #upload_to指定上傳目錄。注意:是上傳到我們配置了的目錄下的哪個目錄(我們這里配置的是static/media目錄)
  • 遷移搔课。

    遷移的注意事項(xiàng):1. 每有一次遷移成功胰柑,就會在diango_migrations表下有一條記錄,在后面繼續(xù)遷移時爬泥,如果發(fā)現(xiàn)該表中已經(jīng)有該記錄柬讨,則不再遷移;2. 如果報xxx表已經(jīng)存在袍啡,就到migrations目錄下的對應(yīng)文件中刪除已經(jīng)存在的表即可

  • 在應(yīng)用下的admin里面注冊模型類

假設(shè)我們通過瀏覽器上傳了圖片踩官,就會發(fā)現(xiàn)該表中多了一跳紀(jì)律,它里面存儲的是相對路徑

用戶自定義上傳圖片

  • 定義用戶上傳圖片的頁面并顯示葬馋,就是自己定義一個表單卖鲤。只有定義 了method和enctype肾扰,才能上傳文件

在模板文件show_upload.html中包含如下代碼:

<form method='post' actioon='/upload_handle' enctype='multipart/form-data'>
<!-- 在/upload_handle這個地址對應(yīng)的視圖函數(shù)里面保存文件 -->
    {% csrf_token %}
    <input type='file' name='pic'><br>
    <input type='submit' value='上傳'>
</form>

視圖函數(shù):

from django.conf import settings    #獲取配置的上傳目錄
def show_upload(request):
    """"顯示上傳圖片的頁面"""
    return render(request,'booktest/show_upload.html')
def upload_handle(request):
    """上傳圖片處理"""

url的配置以及部分模塊的導(dǎo)入省略

admin站點(diǎn)

控制管理頁展示

類ModelAdmin可以控制模型在Admin界面中的展示方式畴嘶,主要包括在列表頁的展示方式、添加修改頁的展示方式集晚。

在應(yīng)用下的admin.py中窗悯,注冊模型類前定義管理類。eg:AreaAdmin

管理類有兩種使用方式:

  • 注冊參數(shù)
  • 裝飾類

注冊參數(shù):在應(yīng)用下的admin.py文件中偷拔,注冊模型類:


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒋院,一起剝皮案震驚了整個濱河市亏钩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌欺旧,老刑警劉巖姑丑,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異辞友,居然都是意外死亡栅哀,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進(jìn)店門称龙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來留拾,“玉大人,你說我怎么就攤上這事鲫尊〕杖幔” “怎么了?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵疫向,是天一觀的道長咳蔚。 經(jīng)常有香客問我,道長鸿捧,這世上最難降的妖魔是什么屹篓? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮匙奴,結(jié)果婚禮上堆巧,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好迁杨,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布革骨。 她就那樣靜靜地躺著,像睡著了一般荒揣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上焊刹,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天系任,我揣著相機(jī)與錄音,去河邊找鬼虐块。 笑死俩滥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贺奠。 我是一名探鬼主播霜旧,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼儡率!你這毒婦竟也來了挂据?” 一聲冷哼從身側(cè)響起以清,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎崎逃,沒想到半個月后掷倔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡个绍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年今魔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片障贸。...
    茶點(diǎn)故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡错森,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篮洁,到底是詐尸還是另有隱情涩维,我是刑警寧澤,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布袁波,位于F島的核電站瓦阐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏篷牌。R本人自食惡果不足惜睡蟋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枷颊。 院中可真熱鬧戳杀,春花似錦、人聲如沸夭苗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽题造。三九已至傍菇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間界赔,已是汗流浹背丢习。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淮悼,地道東北人咐低。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像敛惊,于是被迫代替她去往敵國和親渊鞋。 傳聞我的和親對象是個殘疾皇子绰更,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評論 2 361

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

  • 一瞧挤、Django介紹 1.簡介 Django锡宋,發(fā)音為[`d???ɡ??],是用python語言寫的開源web開發(fā)框...
    阿孝不會飛閱讀 769評論 0 2
  • 前端相關(guān) 展示內(nèi)容:瀏覽器接收后端返回的html文本(經(jīng)過模板渲染)內(nèi)容并在頁面展示.與用戶交互信息:js將用戶產(chǎn)...
    Knight方閱讀 2,849評論 0 1
  • MVT圖解 項(xiàng)目準(zhǔn)備 創(chuàng)建項(xiàng)目 創(chuàng)建應(yīng)用 更換python解釋器:按需選擇 安裝應(yīng)用 本地化 模板路徑在應(yīng)用同級目...
    阿孝不會飛閱讀 786評論 0 2
  • 第十二篇 無行 五行者特恬,金木水火土执俩。無行者,無相無邊無盡癌刽。塵如煙云役首,正世可觀也。塵如幻覺显拜,負(fù)世可查也衡奥。然...
    抱璞子閱讀 1,883評論 2 6
  • 只身千里赴長安 愛恨情仇未敢言 你若有意同歡顏 小酒館里續(xù)杯盞 蘋香已有蓮開信 果見佳人一轉(zhuǎn)身
    害怕黑卻愛上夜閱讀 107評論 0 3