Django.....

来源:https://www.cnblogs.com/tangjian219/archive/2019/11/03/11788941.html
-Advertisement-
Play Games

Django HTTP協議 HTTP請求/響應的步驟: HTTP請求方法 HTTP狀態碼 URL 超文本傳輸協議(HTTP)的統一資源定位符將從網際網路獲取信息的五個基本元素包括在一個簡單的地址中: + 傳送協議。 + 層級URL標記符號(為[//],固定不變) + 訪問資源需要的憑證信息(可省略) ...


Django

HTTP協議

超文本傳輸協議(英文:Hyper Text Transfer Protocol,HTTP)是一種用於分散式、協作式和超媒體信息系統的應用層協議。HTTP是萬維網的數據通信基礎.HTTP有很多應用,最著名的是用於Web瀏覽器伺服器之間的雙工通信.

HTTP是一個客戶端(用戶)和伺服器端(網站)請求和應答的標準(TCP)..

一次請求一次響應就斷開連接,無狀態,短鏈接,格式包括頭和體,請求頭和請求體,響應頭和響應體,請求頭與請求頭之間用一個\r\n,請求頭與請求體用\r\n\r\n

HTTP請求/響應的步驟:

1. 客戶端連接到Web伺服器

   一個HTTP客戶端,通常是瀏覽器,與Web伺服器的HTTP埠(預設為80)建立一個TCP套接字連接.

2. 發送HTTP請求

   通過TCP協議套接字,客戶端向Web伺服器發送一個文本的請求報文,一個請求報文由請求行,請求頭部,空行和請求數據4部分組成.

3. 伺服器接收請求並返回HTTP響應

   Web伺服器解析請求,定位請求資源.伺服器將資源副本寫到TCP套接字,由客戶端讀取.一個響應由狀態行,響應頭部,空行和響應數據4部分組成

4. 釋放連接TCP連接
   若connection 模式為close,則伺服器主動關閉TCP連接,客戶端被動關閉連接,釋放TCP連接;若connection 模式為keepalive,則該連接會保持一段時間,在該時間內可以繼續接收請求;

5. 客戶端瀏覽器解析HTML內容

   客戶端瀏覽器首先解析狀態行,查看表明請求是否成功的狀態代碼。然後解析每一個響應頭,響應頭告知以下為若幹位元組的HTML文檔和文檔的字元集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,併在瀏覽器視窗中顯示。


在瀏覽器地址欄鍵入URL,按下回車之後經歷的流程:
1. 瀏覽器向DNS伺服器請求解析該URL中的功能變數名稱所對應的的IP地址;
2. 解析出IP地址後,根據IP地址和預設埠80,和伺服器建立TCP連接
3. 瀏覽器發出讀取文件(URL中功能變數名稱後面部分對應的文件)的HTTP請求,該請求報文作為TCP三次握手的第三個報文的數據發送給伺服器.
4. 伺服器對瀏覽器請求作出響應,並把對應的HTML文本發送給瀏覽器
5. 釋放TCP連接
6. 瀏覽器將該HTML文本並顯示內容

HTTP請求方法

1. GET

   向指定的資源發出“顯示”請求。使用GET方法應該只用在讀取數據,而不應當被用於產生“副作用”的操作中,例如在Web Application中。其中一個原因是GET可能會被網路蜘蛛等隨意訪問。

2. HEAD

   與GET方法一樣,都是向伺服器發出指定資源的請求。只不過伺服器將不傳回資源的本文部分。它的好處在於,使用這個方法可以在不必傳輸全部內容的情況下,就可以獲取其中“關於該資源的信息”(元信息或稱元數據)。

3. POST

   向指定資源提交數據,請求伺服器進行處理(例如提交表單或者上傳文件)。數據被包含在請求本文中。這個請求可能會創建新的資源或修改現有資源,或二者皆有。

4. PUT

   向指定資源位置上傳其最新內容。

5. DELETE

   請求伺服器刪除Request-URI所標識的資源。

6. TRACE

   回顯伺服器收到的請求,主要用於測試或診斷。

7. OPTIONS

   這個方法可使伺服器傳回該資源所支持的所有HTTP請求方法。用'*'來代替資源名稱,向Web伺服器發送OPTIONS請求,可以測試伺服器功能是否正常運作

8. CONNECT

   HTTP/1.1協議中預留給能夠將連接改為管道方式的代理伺服器。通常用於SSL加密伺服器的鏈接(經由非加密的HTTP代理伺服器)。

HTTP狀態碼

所有HTTP響應的第一行都是狀態行,依次是當前HTTP版本號,3位數字組成的狀態代碼,以及描述狀態的短語,彼此由空格分隔。

狀態代碼的第一個數字代表當前響應的類型:

+ 1xx消息——請求已被伺服器接收,繼續處理

+ 2xx成功——請求已成功被伺服器接收、理解、並接受   ***

+ 3xx重定向——需要後續操作才能完成這一請求

+ 4xx請求錯誤——請求含有詞法錯誤或者無法被執行  

  ​ 404: NOT FIND(伺服器上沒有)  403 伺服器上有,但是沒有許可權  ***

+ 5xx伺服器錯誤——伺服器在處理某個正確請求時發生錯誤

URL

超文本傳輸協議(HTTP)的統一資源定位符將從網際網路獲取信息的五個基本元素包括在一個簡單的地址中:

+ 傳送協議。
+ 層級URL標記符號(為[//],固定不變)
+ 訪問資源需要的憑證信息(可省略)
+ 伺服器 -- (通常為功能變數名稱,有時為IP地址)
+ 埠號 -- (以數字方式表示,若為HTTP的預設值":80",https 埠預設":443"可省略)
+ 路徑 -- (以“/”字元區別路徑中的每一個目錄名稱)
+ 查詢 -- (GET模式的窗體參數,以“?”字元為起點,每個參數以“&”隔開,再以“=”分開參數名稱與數據,通常以UTF8的URL編碼,避開字元衝突的問題)
+ 片段 -- 以“#”字元為起點

`https://www.sogou.com:443/web?query=海水兩邊顏色不同&_asf=www.sogou.com&_ast=&w=01015002&p=40040108&ie=utf8&from=index-nologin&s_from=index&oq=&ri=0&sourceid=sugg&suguuid=&sut=0&sst0=1566374533005&lkt=0%2C0%2C0&sugsuv=0003ECF37B7010FB5D174856999B7817&sugtime=1566374533005`

+ http,是協議;
+ www.sogou.com是功能變數名稱,伺服器
+ 443是伺服器上的網路埠號
+ /web 是路徑
+ ?query=海水兩邊顏色不同 : 問號之後是查詢參數

web框架

web框架的本質 : socket服務端

web框架的功能

1. 使用socket收發消息
2. 根據不同的路徑返回不同的內容
3. 返回動態的數據(字元串的替換 -- 模板的渲染(使用jinja2) )

分類: 
+ Django實現 2 3 功能
+ flask 實現 2 功能
+ tornado 實現 1 2 3功能

伺服器程式和應用程式

對於真實開發中的python web程式來說,一般會分為兩部分:伺服器程式和應用程式。

伺服器程式負責對socket服務端進行封裝,併在請求到來時,對請求的各種數據進行整理。

應用程式則負責具體的邏輯處理。為了方便應用程式的開發,就出現了眾多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程式都要和伺服器程式配合,才能為用戶提供服務。

**WSGI**(Web Server Gateway Interface)就是一種規範,它定義了使用Python編寫的web應用程式與web伺服器程式之間的介面格式,實現web應用程式與web伺服器程式間的解耦。( **跨站請求偽造** )

常用的WSGI伺服器有uWSGI、Gunicorn。而Python標準庫提供的獨立WSGI伺服器叫wsgiref,Django開發環境用的就是這個模塊來做伺服器。

Django處理請求的一個流程

1. 在瀏覽器上輸入地址,回車,發送一個get請求
2. wsgi模塊接受請求,把請求相關的內容封裝成request對象
3. 根據url地址,找到對應的函數
4. 執行函數,得到返回值.wsgi模塊將httpresponse對象按照http響應格式發送給瀏覽器

Django的所有命令

下載安裝

  1. 命令行

    pip3 install django==1.11.23 -i https://pypi.tuna.tsinghua.edu.cn/simple -- (源地址)

  2. pycharm

創建項目

  1. 命令行

    django-admin startproject 項目名稱

  2. pycharm

    flie _ new_project _ django _ 項目路徑 選解釋器

啟動項目

首先切換到項目的根目錄

  1. 命令行

    • python manage.py runserver # 127.0.0.1:8000
    • python manage.py runserver 80 # 127.0.0.1:80 修改埠號
    • python manage.py runserver 0.0.0.0:80 # 0.0.0.0:80 修改IP和埠號
  2. pycharm

    點綠三角 dj --> 不要右鍵運行文件

創建APP

python manage.py startapp app名稱

資料庫遷移

python manage.py makemigrations # 記錄索引APP下的models的變更記錄

python manage.py migrate # 同步遷移記錄

配置

url.py 文件

urls.pyurl 與函數的對應關係,寫函數

from django.shortcuts import HttpResponse,render

def func(request):
    return HttpResponse('返回的字元串')   # 返回字元串

def home(request):
    return render(request,'home.html')   # 返回html頁面

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^func/', func),                # 路徑和函數的對應關係
    url(r'^home/', home),
]

靜態文件的配置

STATIC_URL = '/static/'  # 別名

STATICFILES_DIRS = [     # 按照列表的順序進行查找
    os.path.join(BASE_DIR, 'x1'),
    os.path.join(BASE_DIR, 'static'),
    os.path.join(BASE_DIR, 'x2')
]

登錄的實例

form表單

  1. action -- 提交的地址 , method -- 請求方法 ( 預設是get , 設置post )
  2. input 需要有name屬性 , required表示必須填寫(可以去掉)
  3. submit 提交的按鈕或者input
  4. form表單 novalidate不需要校驗

目前提交post請求,要註釋一個csrf中間件 ( setting.py文件)

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',    # csrf中間件
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

request 和 response( 初識 )

request

# 發送get請求的方式:
- form表單,不指定method
- 在地址欄中直接輸入地址,回車
- a標簽
request.GET # url上攜帶的參數,獲取到的數據是字典形式 ?k1=v1&k2=v2
request.GET.get('k1','xxx') # 獲取某一個參數對應的值,沒有就返回xxx
request.method  # 請求的方法(一般用來做判斷) -- GET POST PUT

#發送post請求:
form表單 : method = 'post'
request.POST  # 獲取所有form表單提交的數據    
request.POST.get('k1','xxx') # 獲取提交數據的某一個值,沒有就返回xxx

response

HttpResponse('字元串')  # 返回字元串
render(request,'模板文件名',{'k1':v1,'k2':v2} # 返回一個完整的頁面
redirect('/URL路徑/')  # 重定向,相當於響應頭 Location:url

app

新建app

python36 manage.py startapp app名字

註冊app

在setting中

INSTALLED_APPS = [
    # 兩種方法
    'app01',  
    'app01.apps.App01Config',  # 推薦寫法
]

目錄:

admin.py      django提供一個 admin工具 
apps.py       app的信息
models.py     模型  model  跟資料庫有關
views.py      寫函數

HTTPRequest對象就是咱們的視圖函數的參數request

    # print(request)  #<WSGIRequest: GET '/home/'>
    # # print(dir(request))
    #
    # print(request.path) #/home/  純路徑
    # print(request.path_info) #/home/  純路徑
    # print(request.get_full_path()) #/home/?a=1&b=2  全路徑(不包含ip地址和埠)

    # print(request.META)  #請求頭相關數據,是一個字典

    # print(request.method)  #GET

    # print(request.GET)
    
    # print(request.POST)
    # print(request.body)  能夠拿到請求數據部分的數據(post,get沒有)

HTTPResponse對象

HTTPResponse('字元串')                       
render(request,'xx.html')

redirect 重定向#用法  redirect(路徑) 示例:redirect('/index/')

FBV和CBV 視圖(視圖函數和視圖類)

類視圖 CBV

views.py

from django.views import View
class LoginView(View):

    # def dispatch(self, request, *args, **kwargs):
    #     print('xx請求來啦!!!!')                  
    #     ret = super().dispatch(request, *args, **kwargs)
    #     print('請求處理的邏輯已經結束啦!!!')
    #     return ret
    def get(self,request):  #處理get請求直接定義get方法,不需要自己判斷請求方法了,源碼中用dispatch方法中使用了反射來處理的
        print('小小小小')
        return render(request,'login.html')

    def post(self,request):
        print(request.POST)
        return HttpResponse('登錄成功')

urls.py路由寫法

url(r'^login/', views.LoginView.as_view()),

視圖加裝飾器

視圖函數FBV
    def wrapper(func):
        def inner(*args, **kwargs):
            print(11111)
            ret = func(*args, **kwargs)
            print(22222)
            return ret
        return inner


    @wrapper
    def index(request):
        print('xxxxx')
        return HttpResponse('indexxxxxxxxx')

視圖類CBV
    from django.utils.decorator import method_decorator
    @method_decorator(wrapper,name='get')  # 方式3
    class LoginView(View):
        @method_decorator(wrapper) #方式2
        def dispatch(self, request, *args, **kwargs):
            print('xx請求來啦!!!!')  
       
            ret = super().dispatch(request, *args, **kwargs)
        
            print('請求處理的邏輯已經結束啦!!!')
            return ret
        @method_decorator(wrapper)  #方式1
        def get(self,request):
            print('小小小小')
            return render(request,'login.html')

        def post(self,request):
            print(request.POST)
            return HttpResponse('登錄成功')

模板渲染

{{ 變數 }}   {% 邏輯 %} -- 標簽

萬能的點

<h1>91李業網</h1>
<h2>{{ name }}</h2>
<h2>{{ d1.items }}</h2>
<h2>我是"{{ l1.1 }}"</h2>
<h2>{{ num }}</h2>
<h2>{{ obj.p }}</h2>  #如果調用的方法需要傳參,sorry用不了

過濾器(內置)

參考博客:https://www.cnblogs.com/clschao/articles/10414811.html
1.default
    如果一個變數是false或者為空,使用給定的預設值。 否則,使用變數的值。

       {{ value|default:"nothing"}}
    如果value沒有傳值或者值為空的話就顯示nothing

2.length
    返回值的長度,作用於字元串和列表。
    {{ value|length }}
    返回value的長度,如 value=['a', 'b', 'c', 'd']的話,就顯示4.

3.filesizeformat
    將值格式化為一個 “人類可讀的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
       {{ value|filesizeformat }}
    如果 value 是 123456789,輸出將會是 117.7 MB。

4.slice
    切片,如果 value="hello world",還有其他可切片的數據類型
       {{value|slice:"2:-1"}}

5.date
    格式化,如果 value=datetime.datetime.now()

       {{ value|date:"Y-m-d H:i:s"}}
      關於時間日期的可用的參數(除了Y,m,d等等)還有很多,有興趣的可以去查查看看。

6.safe
    Django的模板中在進行模板渲染的時候會對HTML標簽和JS等語法標簽進行自動轉義,原因顯而易見,這樣是為了安全,django擔心這是用戶添加的數據,比如如果有人給你評論的時候寫了一段js代碼,這個評論一提交,js代碼就執行啦,這樣你是不是可以搞一些壞事兒了,寫個彈窗的死迴圈,那瀏覽器還能用嗎,是不是會一直彈窗啊,這叫做xss攻擊,所以瀏覽器不讓你這麼搞,給你轉義了。但是有的時候我們可能不希望這些HTML元素被轉義,比如我們做一個內容管理系統,後臺添加的文章中是經過修飾的,這些修飾可能是通過一個類似於FCKeditor編輯加註了HTML修飾符的文本,如果自動轉義的話顯示的就是保護HTML標簽的源文件。為了在Django中關閉HTML的自動轉義有兩種方式,如果是一個單獨的變數我們可以通過過濾器“|safe”的方式告訴Django這段代碼是安全的不必轉義。
    我們去network那個地方看看,瀏覽器看到的都是渲染之後的結果,通過network的response的那個部分可以看到,這個a標簽全部是特殊符號包裹起來的,並不是一個標簽,這都是django搞得事情。
    比如:
    value = "<a href='#'>點我</a>"   和   value="<script>alert('123')</script>"
       {{ value|safe}}
    很多網站,都會對你提交的內容進行過濾,一些敏感辭彙、特殊字元、標簽、黃賭毒辭彙等等,你一提交內容,人家就會檢測你提交的內容,如果包含這些辭彙,就不讓你提交,其實這也是解決xss攻擊的根本途徑,例如博客園:

 
7.truncatechars
    如果字元串字元多於指定的字元數量,那麼會被截斷。截斷的字元串將以可翻譯的省略號序列(“...”)結尾。
    參數:截斷的字元數
        {{ value|truncatechars:9}} #註意:最後那三個省略號也是9個字元裡面的,也就是這個9截斷出來的是6個字元+3個省略號,有人會說,怎麼展開啊,配合前端的點擊事件就行啦
        
8.truncatewords
    在一定數量的字後截斷字元串,是截多少個單詞。
    例如:‘hello girl hi baby yue ma’,
       {{ value|truncatewords:3}}  #上面例子得到的結果是 'hello girl h1...'

9.cut
    移除value中所有的與給出的變數相同的字元串
       {{ value|cut:' ' }}
    如果value為'i love you',那麼將輸出'iloveyou'.

11.join
    使用字元串連接列表,{{ list|join:', ' }},就像Python的str.join(list)

12.timesince(瞭解)
    將日期格式設為自該日期起的時間(例如,“4天,6小時”)。

    採用一個可選參數,它是一個包含用作比較點的日期的變數(不帶參數,比較點為現在)。 例如,如果blog_date是表示2006年6月1日午夜的日期實例,並且comment_date是2006年6月1日08:00的日期實例,則以下將返回“8小時”:

{{ blog_date|timesince:comment_date }}
    分鐘是所使用的最小單位,對於相對於比較點的未來的任何日期,將返回“0分鐘”。

13.timeuntil(瞭解)
    似於timesince,除了它測量從現在開始直到給定日期或日期時間的時間。 例如,如果今天是2006年6月1日,而conference_date是保留2006年6月29日的日期實例,則{{ conference_date | timeuntil }}將返回“4周”。

    使用可選參數,它是一個包含用作比較點的日期(而不是現在)的變數。 如果from_date包含2006年6月22日,則以下內容將返回“1周”:

       {{ conference_date|timeuntil:from_date }}

標簽

for迴圈標簽

迴圈列表等
{% for person in person_list %}
    <p>{{ person.name }}</p>  <!--凡是變數都要用兩個大括弧括起來-->
{% endfor %}
迴圈字典
{% for key,val in dic.items %}
    <p>{{ key }}:{{ val }}</p>
{% endfor %}

empty
{% for person in person_list %}
    <p>{{ person.name }}</p>  <!--凡是變數都要用兩個大括弧括起來-->
{% empty %}
    <p>沒有找到東西!</p>
{% endfor %}


forloop.counter            當前迴圈的索引值(從1開始),forloop是迴圈器,通過點來使用功能
forloop.counter0           當前迴圈的索引值(從0開始)
forloop.revcounter         當前迴圈的倒序索引值(從1開始)
forloop.revcounter0        當前迴圈的倒序索引值(從0開始)
forloop.first              當前迴圈是不是第一次迴圈(布爾值)
forloop.last               當前迴圈是不是最後一次迴圈(布爾值)
forloop.parentloop         本層迴圈的外層迴圈的對象,再通過上面的幾個屬性來顯示外層迴圈的計數等
示例:
    {% for i in d2 %}
        {% for k,v in d1.items %}

            <li>{{ forloop.counter }}-- {{ forloop.parentloop.counter }} === {{ k }} -- {{ v }}</li>

        {% endfor %}

    {% endfor %}

if判斷標簽

{% if num > 100 or num < 0 %}
    <p>無效</p>  <!--不滿足條件,不會生成這個標簽-->
{% elif num > 80 and num < 100 %}
    <p>優秀</p>
{% else %}  <!--也是在if標簽結構裡面的-->
    <p>湊活吧</p>
{% endif %}

if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,註意條件兩邊都有空格。

with

方法1
{% with total=business.employees.count %}  #註意等號兩邊不能有空格
    {{ total }} <!--只能在with語句體內用-->
{% endwith %}
方法2
{% with business.employees.count as total %}
    {{ total }}
{% endwith %}

自定義過濾器(@register.filter )

無參數的自定義過濾器
1.先在app文件夾下建立templatetags的文件夾
2.在改文件夾下建立任意名稱的py文件,例如:myfilter.py
    from django import template    導入該文件
    from django.shortcuts import render
    register = template.Library()    註冊器
    @register.filter                 裝飾器,寫了這個就會把下麵的函數定義成一個自定義過濾器
    def addstr(v1):                  要寫參數
        return v1+'oo'               對參數的內容進行加工
3.在urls寫路由對應關係     
4.在app文件夾下的view文件下寫對應函數
def son(request):
    return render(request,'son.html',{'name':'八戒'})
    要把需要加工的內容,傳遞給需要展示出來的HTML文件,son.html
    
5.(1)在對應的HTML文件里先導入自定義過濾器的py文件:{% load myfilter %}
  (2){{ name|addstr }},這裡的name是view文件下的son函數return傳過來的內容
   addstr是myfilter文件里的addrstr的函數返回值 return v1+'oo' 就是在name的基礎上加了oo,返回給HTML



有參數的自定義過濾器
1.先在app文件夾下建立templatetags的文件夾
2.在改文件夾下建立任意名稱的py文件,例如:myfilter.py
    from django import template    導入該文件
    from django.shortcuts import render
    register = template.Library()    註冊器
    @register.filter                 裝飾器,寫了這個就會把下麵的函數定義成一個自定義過濾器
    def addstr(v1,v2):               要寫參數,最多兩個
        return v1+v2                 對參數的內容進行加工
3.在urls寫路由對應關係     
4.在app文件夾下的view文件下寫對應函數
def son(request):
    return render(request,'son.html',{'name':'八戒'})
    要把需要加工的內容,傳遞給需要展示出來的HTML文件,son.html
    
5.(1)在對應的HTML文件里先導入自定義過濾器的py文件:{% load myfilter %}
  (2){{ name|addstr:'oo' }},這裡的name是view文件下的son函數return傳過來的內容,oo為第二個參數
   addstr是myfilter文件里的addrstr的函數返回值 return v1+v2 ,v1是name對應的內容,v2是第二個參數oo,
   addstr對兩個參數進行加工,即:八戒oo,返回給HTML
        

自定義標簽( @register.simple_tag)

1.在myfilter中寫自定義標簽的函數
    from django import template
    from django.shortcuts import render
    register = template.Library()
    @register.simple_tag  自定義標簽
    def mytag(n1,n2):     參數沒有限制
        return n1+n2      把參數進行進行加工
        
2.先導入這個文件 -->{% load myfilter %}
    使用這個自定義標簽 {% mytag name '真好' %}
    mytag是自定義標簽的函數
    name是view函數中的return返回給HTML的值
    '真好'是另一個參數,並對原來數據進行加工
    return n1+n2  加工

返回html片段的標簽(@inclusion_tag )

在不加url的情況下,想用son.html文件,但是想把result.html作為一個組件引入到son.html
過程:
1.建立路由關係
2.views函數
    def res(request):
        return render(request,'son.html')
3.首先在son.html使用了 inclusion_tag :{% res 's1' 's2' %},會先找到res函數,執行這個函數,得到一個返回值
4.這個返回值不會交給son.html的res,而是先交給@register.inclusion_tag('result.html')的result.html,
5.在result.html進行渲染,渲染完成之後會生產一個標簽,才會作為一個組件生成到son.html中,
6.所以在son.html有了result.html東西.

靜態文件配置

1 項目目錄下創建一個文件夾,例如名為jingtaiwenjianjia,將所有靜態文件放到這個文件夾中
2 settings配置文件中進行下麵的配置
    # 靜態文件相關配置
    STATIC_URL = '/abc/'  #靜態文件路徑別名

    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'jingtaiwenjianjia'),
    ]

3 引入<link rel="stylesheet" href="/abc/css/index.css">

url別名和反向解析

寫法
    url(r'^index2/', views.index,name='index'),
反向解析
    後端: from django.urls import reverse
         reverse('別名')  例如:reverse('index') -- /index2/
    html: {% url '別名' %} -- 例如:{% url 'index' %} -- /index2/

url命名空間

路由分發 include

1 在每個app下創建urls.py文件,寫上自己app的路徑
2 在項目目錄下的urls.py文件中做一下路徑分發,看下麵內容
    from django.conf.urls import url,include
    from django.contrib import admin

    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'^app01/', include('app01.urls')),#app01/home/
        url(r'^app02/', include('app02.urls')),
    ]

命名空間namespace

from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^app01/', include('app01.urls',namespace='app01')),#app01/home/
    url(r'^app02/', include('app02.urls',namespace='app02')),   
]

新建app01和app02
在app01新建urls和app02新建urls
在app01的views寫對應函數
在app02的views寫對應函數

使用:
    後端:reverse('命名空間名稱:別名') -- reverse('app01:home') 
    hmtl:{% url '命名空間名稱:別名' %}  -- {% url 'app01:home' %}

orm單表操作

orm簡介

對象關係映射(Object Relational Mapping,簡稱ORM)它實現了數據模型與資料庫的解耦,即數據模型的設計不需要依賴於特定的資料庫,通過簡單的配置就可以輕鬆更換資料庫,這極大的減輕了開發人員的工作量,不需要面對因資料庫變更而導致的無效勞動

簡單的說,ORM是通過使用描述對象和資料庫之間映射的元數據,將程式中的對象自動持久化到關係資料庫中。

ORM解決的主要問題是對象和關係的映射。它通常將一個類和一張表一一對應,類的每個實例對應表中的一條記錄,類的每個屬性對應表中的每個欄位。 
ORM提供了對資料庫的映射,不用直接編寫SQL代碼,只需操作對象就能對資料庫操作數據。

ORM在業務邏輯層和資料庫層之間充當了橋梁的作用

使用mysql資料庫的流程

  1. 創建一個mysql資料庫

    註意 : setting.py文件中的 TEMPLATES 的 DIR 路徑

  2. 在settings中配置資料庫

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql', # 引擎
            'NAME': 'day54',                 # 資料庫名稱
            'HOST': '127.0.0.1',                  # IP
            'PORT': 3306,                         # 埠號
            'USER': 'root',                       # 用戶名
            'PASSWORD': '123'                     # 密碼
        }
    }
    
    
    
    會在控制臺上列印原生sql語句
    LOGGING = {
        'version':1,
        'disable_existing_loggers':False,
        'handlers':{
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers':{
            'django.db.backends':{
                'handlers':['console'],
                'propagate':True,
                'level':'DEBUG',
            }
        }
    
    }
  3. 使用pymysql模塊連接資料庫

    # 寫在與setting同級目錄下的init.py中
    
    import pymysql
    pymysql.install_as_MySQLdb()
  4. 寫對應關係,在app下的models.py中寫類

    class User(models.Model):
        username = models.CharField(max_length=32) # varchar類型(長度32)
        password = models.CharField(max_length=32) # varchar類型(長度32)
        # 外鍵的創建
        pub = models.ForgienKey('Publisher',on_delete=models.CASCADE)  # on_delete 2.0版本以上必填
  5. 執行資料庫遷移的命令

    python36 manage.py makemigrations  # 記錄下models.py的變更,創建遷移文件
    python36 manage.py migrate         # 將變更記錄同步到資料庫中,遷移

django操作原生sql語句

ret = models.Book.objects.raw('select * from app where id = 2')
print(ret)
輸出的是queryset對象
可以for迴圈取值


from django.db import connection

cursor=connection.cursor()

# 插入操作
cursor.execute("insert into hello_author(name) values('錢鐘書')")

# 更新操作
cursor.execute("update hello_author set name='abc' where name='bcd'")

# 刪除操作
cursor.execute("delete from hello_author where name='abc'")

# 查詢操作
cursor.execute("select * from hello_author")

raw=cursor.fetchone()  # 返回結果行游標直讀向前,讀取一條
cursor.fetchall()  # 讀取所有

orm對資料庫的增刪改查

1.先要通過mysql的sql語句在終端中創建庫
創建一個表 = 在app下的models寫個類
class UserInfo(models.Model):
     id = models.AutoField(primary_key=True)
     name = models.CharField(max_length=10)
     bday = models.DateField()
     checked = models.BooleanField()
 2.在manage.py下的Terminal寫資料庫同步指令(方法一)
        python manage.py makemigrations
         python manage.py migrate
    在pycharm中的Tools下的Run manage Taskd點擊,在下麵寫makemigrations和migrate兩條指令(方法二)

*********增**********
方式1:
    new_obj = models.UserInfo(
        id=2,
        name='八戒',
        bday='2019-09-27',
        checked=1,
    )
    new_obj.save() # 翻譯成sql語句,然後調用pymysql,發送給服務端
方式2:
    # ret 是創建的新的記錄的model對象(重點)
    print(ret)  #UserInfo object  莎莎
    print(ret.name)  #UserInfo object
    print(ret.bday)  #UserInfo object

批量增加:
    obj_list = []

    for i in range(10):
        obj = models.Book(
            title='xx'
        )
        obj_list.append(obj)
    models.Book.objects.bulk_create(obj_list)   
    
********刪********
簡單查詢:filter()  -- 結果是queryset類型的數據裡面是一個個的model對象,類似於列表
    models.UserInfo.objects.filter(id=7).delete()     #queryset對象調用
    models.UserInfo.objects.filter(id=7)[0].delete()  #model對象調用

********改********
方式1:update
     models.UserInfo.objects.filter(id=2).update(
         name='籃子',
         checked = 0,  checked可以看出一個判斷條件
    
     )
     錯誤示例,model對象不能調用update方法
     models.UserInfo.objects.filter(id=2)[0].update(
         name='加籃子+2',
        
     )
方式2 
    ret = models.UserInfo.objects.filter(id=2)[0]
    ret.name = '加籃子+2'
    ret.save()
print(models.ttt.objects.filter(pid=2))----><QuerySet [<ttt: ttt object>]>對象集合
print(models.ttt.objects.filter(pid=2)[0]) --->ttt object對象,可以進行操作
更新時的auto_now參數
    # 更新記錄時,自動更新時間,創建新紀錄時也會幫你自動添加創建時的時間,但是在更新時只有使用save方法的方式2的形式更新才能自動更新時間,有缺陷,放棄
    now2 = models.DateTimeField(auto_now=True,null=True)
    
    
********查*********
all()  queryset
filter(id=1,name='xx')  and  queryset
get()  model對象 
customer.get_sex_display #sex_type = (('male', '男'), ('female', '女'))   取男女
count()
first()
last()
exclude() exclude(id=1)
exists()  False  True
order_by('id','-price')
reverse() 反轉,先排序
values()  -- queryset([{},{}])
values_list() queryset([(),()])
distinct()


filter 雙下劃線查詢
filter(price__gt=30)
filter(price__gte=30)
filter(price__lt=30)
filter(price__lte=30)
filter(price__range=[30,40])
filter(price__in=[30,40,50..])
filter(title_contains='py')
filter(title_icontains='py')
filter(title_istartswith='py')
filter(title_iendswith='py')
filter(pub_date__year__gt='2018',pub_date__month='09',pub_date__day='09')

增加

    # 一對一
    # au_obj = models.AuthorDetail.objects.get(id=4)
    models.Author.objects.create(
        name='海狗',
        age=59,
        # 兩種方式
        au_id=4
        # au=au_obj
    )

    # 一對多
    # pub_obj = models.Publish.objects.get(id=3)
    #
    # models.Book.objects.create(
    #     title='xx2',
    #     price=13,
    #
    #     publishDate='2011-11-12',
    #     # publishs=pub_obj , #類屬性作為關鍵字時,值為model對象
    #     publishs_id=3  # 如果關鍵字為資料庫欄位名稱,那麼值為關聯數據的值
    # )

    # 多對多  -- 多對多關係表記錄的增加
    # ziwen = models.Author.objects.get(id=3)
    # haigou = models.Author.objects.get(id=5)

    new_obj = models.Book.objects.create(
        title='海狗產後護理第二部',
        price=0.5,
        publishDate='2019-09-29',
        publishs_id=2,
    )

    new_obj.authors.add(3,5)  #  #*args  **kwargs
    new_obj.authors.add(*[3,5])  # 用的最多,
    new_obj.authors.add(ziwen, haigou)

刪除

    # 一對一
    # models.AuthorDetail.objects.filter(id=3).delete()
    # models.Author.objects.filter(id=3).delete()
    # 一對多
    # models.Publish.objects.filter(id=3).delete()
    # models.Book.objects.filter(id=4).delete()

    # 多對多
    book_obj = models.Book.objects.get(id=2)
    # book_obj.authors.add()  # 添加
    # book_obj.authors.remove(1)  #刪除
    # book_obj.authors.clear()  # 清除
    # book_obj.authors.set(['1','5'])  # 先清除再添加,相當於修改

    # 改
    # ret = models.Publish.objects.get(id=2)
    # models.Book.objects.filter(id=5).update(
    #     # title='華麗麗',
    #     publishs=ret,
    #     # publishs_id=1,
    # )

基於對象的跨表查詢

    # 查詢
    # 一對一
    # 關係屬性寫在表1,關聯到表2,那麼通過表1的數據去找表2的數據,叫做正向查詢,返過來就是反向查詢
    # 查詢一下王洋的電話號碼

    # 正向查詢  對象.屬性
    # obj = models.Author.objects.filter(name='王洋').first()
    # ph = obj.au.telephone
    # print(ph)

    # 查一下電話號碼為120的作者姓名
    # 反向查詢  對象.小寫的表名
    # obj = models.AuthorDetail.objects.filter(telephone=120).first()
    # ret = obj.author.name  #陳碩
    # print(ret)

    # 一對多
    # 查詢一下 海狗的慫逼人生這本書是哪個出版社出版的  正向查詢
    # obj = models.Book.objects.filter(title='海狗的慫逼人生').first()
    # ret = obj.publishs.name
    # print(ret)  #24期出版社
    #  查詢一下 24期出版社出版過哪些書
    # obj = models.Publish.objects.filter(name='24期出版社').first()
    #
    # ret = obj.book_set.all() #<QuerySet [<Book: 母豬的產後護理>, <Book: 海狗的慫逼人生>]>
    # for i in ret:
    #     print(i.title)

    # 多對多
    # 海狗的慫逼人生 是哪些作者寫的 -- 正向查詢
    # obj = models.Book.objects.filter(title='海狗的慫逼人生').first()
    # ret = obj.authors.all()
    #
    # print(ret)  #<QuerySet [<Author: 王洋>, <Author: 海狗>]>
    # for i in ret:
    #     print(i.name)

    # 查詢一下海狗寫了哪些書 -- 反向查詢
    # obj = models.Author.objects.filter(name='海狗').first()
    # ret = obj.book_set.all()
    # print(ret)
    # for i in ret:
    #     print(i.publishs.name)
    #     print(i.title)
    # return HttpResponse('ok')

用admin操作資料庫

admin添加用戶

執行run manage.py Task和資料庫遷移指令一樣

輸入:python manage.py createsuperuser創建admin用戶

輸入用戶名:tangjian
郵箱不用輸 直接回車
輸入密碼:必須超過8位,並且別太簡單

admin註冊

admin.py把資料庫中的表註冊到admin

from django.contrib import admin
# Register your models here.
from app01 import models

admin.site.register(models.Author)
admin.site.register(models.AuthorDetail)
admin.site.register(models.Publish)
admin.site.register(models.Book)

註冊成功後啟動項目,在url中輸入.../admin/, 登錄

1571404106208

1571404525649

1571404666455

admin解決忘記密碼

在manage.py的Terminal輸入以下命令:前提記得用戶名
python3 manage.py shell

from django.contrib.auth.models import User

user = User.objects.get(username='soog')

user.set_password('4560000')

user.save()

聚合查詢和分組查詢

聚合查詢

寫之前先導入聚合函數 from django.db.models import Max,Min,Count,Avg,Sum
   
    print(models.book.objects.aggregate(Max('price')))  #{'price__max': Decimal('89.00')}
    print(models.book.objects.aggregate(Min('price')))  #{'price__min': Decimal('23.00')}
    print(models.book.objects.aggregate(Sum('price')))  #{'price__sum': Decimal('237.00')}
    print(models.book.objects.filter(pk__range=[1,3]).aggregate(Max('price'),Min('price'))) #pk__range=[1,3]範圍查詢,在pk值為1-3中的最大值,能取到3
    print(models.book.objects.aggregate(Count('price'))) #{'price__count': 5}
    print(models.book.objects.aggregate(Avg('price')))  #{'price__avg': 48.4}

分組查詢

sql語句中用group by分組
 統計每本書的作者的個數
    ret = models.book.objects.annotate(Count('book_author')).values()  #annotate是給book添加新增欄位,count,但只是在查詢的時候會顯示(values()查詢)

    統計每個出版社的最便宜的書
    方法一
    ret = models.publish.objects.annotate(Min('book__price')).values()

    方法二
    #也可以用for迴圈代替values()取值
    #values('book_author')指定分組,分組條件,values放前面是指定分組條件,放後邊是取值(大多數情況)
    ret = models.book.objects.values('book_publish__p_name').annotate(Min('price'))
    for i in ret:
        print(i)


    統計不止一個的作者圖書
    ret = models.book.objects.annotate(count=Count('book_author')).filter(count__gt=1)
    print(ret)

    查詢各個作者的書的總價格
    方法一:
    ret = models.author.objects.annotate(Sum('book__price')).values()
    print(ret)

    方法二:
    ret = models.book.objects.values('book_author').annotate(Sum('price'))
    print(ret) 

F和Q查詢

    # F查詢,比較兩個欄位之間的內容.sale__gt=F('num') sale>num
     ret = models.book.objects.filter(num__lt=F('sale'))
     print(ret)


    # 對sale數據進行修改,例如:全部銷量+10
    # 這種方法比較複雜
     ret= models.book.objects.all()
     for i in ret:
         i.sale = i.sale+10
         i.save()


    # F對某一個欄位的每一個值進行操作
     models.book.objects.update(sale=F('sale')+10)

    # Q查詢
    # 查詢pk值大於5或小於2的對象,Q表示 或
    ret = models.book.objects.filter(Q(pk__gt=2)|Q(pk__lt=5))
    print(ret)

事務

from django.db import transaction

try:
    with transaction.atomic():
        # orm操作
        book1 = models.Book.objects.get(pk=1)
        book2 = models.Book.objects.get(pk=2)

        book1.num -= 20
        book1.save()
        int('sss')     #轉賬過程中模擬發生錯誤
        book2.num += 20
        book2.save()
except Exception as e:
    print(e)
Cookie和Session其實是共通性的東西,不限於語言和框架
定義: 保存在瀏覽器上的一組組鍵值對. k1=v1

Cookie是由伺服器發給客戶端的特殊信息,而這些信息以文本文件的方式存放在客戶端,然後客戶端每次向伺服器發送請求的時候都會帶上這些特殊的信息(鍵值對),用於伺服器記錄客戶端的狀態

Cookie無論是伺服器發給瀏覽器還是瀏覽器發給伺服器,都是放在請求頭中的,記錄著用戶的登錄狀態

為什麼要使用cookie?

http協議是無狀態的,每次的請求相對獨立,之間沒有關係. 沒有辦法保存狀態

特性:

cookie的工作原理是:由伺服器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣伺服器就能通過Cookie的內容來判斷這個是“誰”了。

  • 伺服器讓瀏覽器進行設置,瀏覽器也有權不設置
  • 保存在瀏覽器本地
  • 下次訪問時自動攜帶對應的cookie

應用:

  • 登錄
  • 投票
  • 記錄網頁瀏覽習慣
  • 會話狀態管理(如用戶登錄狀態、購物車、游戲分數或其它需要記錄的信息)
  • 個性化設置(如用戶自定義設置、主題等)
  • 瀏覽器行為跟蹤(如跟蹤分析用戶行為等

應用示例:

from django.shortcuts import render, redirect, HttpResponse
import functools
def login_required(func):
    @functools.wraps(func)   #裝飾器需要加的
    def inner(request, *args, **kwargs):
        # 獲取cookie值
        # is_login = request.COOKIES.get('is_login')
        # 獲取session
        is_login = request.session.get('is_login')
        print(is_login)
        print(request.session.items())
        print(request.session.session_key)
        if is_login != '1000':
            return redirect(f'/login/?returnurl={request.path_info}')
        ret = func(request, *args, **kwargs)
        return ret
    return inner


def login(request):
    request.session.clear_expired()  # 清除失效數據
    if request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'Agoni' and pwd == '123':
            # 獲取是否有跳轉的地址
            returnurl = request.GET.get('returnurl')  # 獲取url上的參數的值 '/url/'
            if returnurl:
                ret = redirect(returnurl)
            else:
                ret = redirect('/home/')
            # 設置cookie,通過響應對象設置
            # ret.set_cookie('is_login', '1000')  # Set_Cookie: is_login=1000; Path=/ 設置響應頭
            # ret['Set_Cookie'] = 'is_login=1000; path=/'
            # 設置session,用request,按照字典的方式設置
            request.session['is_login'] = '1000'
            request.session['user'] = 'coco'
            return ret
        return render(request, 'login.html', {'error': '輸入有誤,請重新輸入'})
    return render(request, 'login.html')


@login_required
def home(request):
    # 讀取cookie
    # is_login = request.COOKIES.get('is_login')
    # 判斷是否登錄
    # if is_login != '1000':
    #     return redirect('/login/')
    return HttpResponse('HOME OK')


@login_required
def index(request):
    # is_login = request.COOKIES.get('is_login')
    # if is_login != '1000':
    #     return redirect('/login/')
    return HttpResponse('INDEX OK')


def loginout(request):
    # 刪除cookie
    ret = redirect('/login/')
    # ret.delete_cookie('is_login')  # 通過key刪除對應的cookie
    # request.session.delete()
    request.session.flush()
    return ret

Django中操作cookie

  1. 設置

    ret = rendicter('/home/')  # 響應對象
    ret.set_cookie('is_login', '1000') / ret['Set-Cookie'] = 'is_login=1000; path=/'
    # 參數
    max_age=None   # 設置超時時間,不設置預設關閉瀏覽器就失效
    path='/'       # Cookie生效的路徑,/ 表示根路徑,可指定url
    
    domain=None    # Cookie生效的功能變數名稱
    secure=False   # 設置True只允許https傳輸攜帶cookie
    httponly=False # 設置為True 只能http協議傳輸,無法被JavaScript獲取
  2. 獲取

    # 相當於字典來獲取cookie值
    request.COOKIE.get('is_login')
    request.COOKIE[key]
  3. 刪除

    ret = redirect('/login/')
    ret.delete_cookie('is_login')
# 設置加密cookie
ret.set_signed_cookie('is_login','1000',salt='s1')

# 獲取加密cookie
request.get_sigined_cookie('is_login',default='',salt='s1')

session

定義: 保存在伺服器上一組組鍵值對,必須依賴於cookie

session 的運行依賴 session id,而 session id 是存在 cookie 中的,也就是說,如果 瀏覽器禁用了 cookie ,同時 session 也會失效(當然也可以在 url 中傳遞)

為什麼要用session?

  1. cookie保存在瀏覽器上,不安全

    瀏覽器對cookie的大小有限制,最大位元組數4096

  2. session支持更多的位元組

    保存在伺服器

    有較高的安全性

  3. session實現機制

    • 依賴於cookie
    • session將數據保存在服務端
    • 當用戶發送請求時,在服務端會生產隨機字元串,並開闢一塊記憶體空間,存儲個人數據,隨機字元串會基於cookie返回給瀏覽器

session流程解析

img

Django中操作session

  1. 設置

    request.session['is_login']='1000'
  2. 獲取

    request.session['is_login']
    request.session.get('is_login')  ***
    request.session.session_key   獲取sessionid隨機字元串
  3. 刪除

    request.session.delete() # 刪除session數據,不刪除cookie
    request.session.flush()  # 刪除session數據,刪除cookie

Django中session相關方法

# 獲取、設置、刪除Session中數據
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在則不設置
del request.session['k1']
request.session.pop(key)

# 獲取所有 鍵、值、鍵值對
request.session.keys()
request.session.values()
request.session.items()

# 獲取會話session的key,隨機字元串
request.session.session_key  

# 將所有Session失效日期小於當前日期的數據刪除 
request.session.clear_expired()   ***

# 檢查會話session的key在資料庫中是否存在
request.session.exists("session_key")

# 刪除當前會話的所有Session數據
request.session.delete()
  
# 刪除當前的會話數據並刪除會話的Cookie。
request.session.flush() 
    這用於確保前面的會話數據不可以再次被用戶的瀏覽器訪問
    例如,django.contrib.auth.logout() 函數中就會調用它。

# 設置會話Session和Cookie的超時時間
request.session.set_expiry(value)   ***
    * 如果value是個整數,session會在些秒數後失效。
    * 如果value是個datatime或timedelta,session就會在這個時間後失效。
    * 如果value是0,用戶關閉瀏覽器session就會失效。
    * 如果value是None,session會依賴全局session失效策略。

session配置

SESSION_COOKIE_NAME = 'sessionid' # 修改唯一表示cookie名字
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2  # 設置cookie超時時間
SESSION_SAVE_EVERY_REQUEST = True  # 發送請求時(每次訪問),更新超時時間
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 關閉瀏覽器時.cookie是否失效
SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # session存儲引擎 (cache-緩存,cache_db-緩存+資料庫,db-資料庫,file-文件,signed_cookies-加密cookie)

cookie和session的優缺點

使用cookie的缺點:
    如果瀏覽器使用的是cookie,那麼所有的數據都保存在瀏覽器端,
    cookie可以被用戶禁止
    cookie不安全(對於敏感數據,需要加密)
    cookie只能保存少量的數據(大約是4k),cookie的數量也有限制(大約是幾百個),不同瀏覽器設置不一樣,反正都不多
    cookie只能保存字元串
    對伺服器壓力小

使用session的缺點
    一般是寄生在Cookie下的,當Cookie被禁止,Session也被禁止
    當然可以通過url重寫來擺脫cookie
    當用戶訪問量很大時,對伺服器壓力大
    我們現在知道session是將用戶信息儲存在伺服器上面,如果訪問伺服器的用戶越來越多,那麼伺服器上面的session也越來越多, session會對伺服器造成壓力,影響伺服器的負載.如果Session內容過於複雜,當大量客戶訪問伺服器時還可能會導致記憶體溢出。
    用戶信息丟失, 或者說用戶訪問的不是這台伺服器的情況下,就會出現資料庫丟失.

Cookie與Session問答

Cookie運行在客戶端,Session運行在服務端,對嗎?A:不完全正確。Cookie是運行在客戶端,有客戶端進行管理;Session雖然是運行在伺服器端,但是sessionID作為一個Cookie是存儲在客戶端的。

瀏覽器禁止Cookie,Cookie就不能用了,但Session不會受瀏覽器影響,對嗎?A:錯。瀏覽器禁止Cookie,Cookie確實不能用了,Session會受瀏覽器端的影響。很簡單的實驗,在登錄一個網站後,清空瀏覽器的Cookie和隱私數據,單機後臺的連接,就會因為丟失Cookie而退出。當然,有辦法通過URL傳遞Session。

瀏覽器關閉後,Cookie和Session都消失了,對嗎?A:錯。存儲在記憶體中額Cookie確實會隨著瀏覽器的關閉而消失,但存儲在硬碟上的不會。更頑固的是Flash Cookie,不過現在很多系統優化軟體和新版瀏覽器都已經支持刪除Flash Cookie。百度採用了這樣的技術記憶用戶:Session在瀏覽器關閉後也不會消失,除非正常退出,代碼中使用了顯示的unset刪除Session。否則Session可能被回收,也有可能永遠殘留在系統中。

Session 比 Cookie 更安全嗎? 不應該大量使用Cookie嗎?A:錯誤。Cookie確實可能存在一些不安全因素,但和JavaScript一樣,即使突破前端驗證,還有後端保障安全。一切都還要看設計,尤其是涉及提權的時候,特別需要註意。通常情況下,Cookie和Session是綁定的,獲得Cookie就相當於獲得了Session,客戶端把劫持的Cookie原封不動地傳給伺服器,伺服器收到後,原封不動地驗證Session,若Session存在,就實現了Cookie和Session的綁定過程。因此,不存在Session比Cookie更安全這種說法。如果說不安全,也是由於代碼不安全,錯誤地把用作身份驗證的Cookie作為許可權驗證來使用。

Session是創建在伺服器上的,應該少用Session而多用Cookie,對嗎?A:錯。Cookie可以提高用戶體驗,但會加大網路之間的數據傳輸量,應儘量在Cookie中僅保存必要的數據。

如果把別人機器上的Cookie文件複製到我的電腦上(假設使用相同的瀏覽器),是不是能夠登錄別人的帳號呢?如何防範?A:是的。這屬於Cookie劫持的一種做法。要避免這種情況,需要在Cookie中針對IP、UA等加上特殊的校驗信息,然後和伺服器端進行比對。

django請求生命周期大致流程

情況一:沒有model和HTML
瀏覽器發送請求到django的wsgi(wsgi接收瀏覽器發過來的請求,是一個外部伺服器),wsgi接收到這個請求,然後封裝成request對象,request對象走url路由匹配,路由匹配成功後走視圖函數,執行視圖函數,把http這個對象變成字元串(http相應格式的字元串),最後變成bytes類型發給瀏覽器

情況二:有model和HTML
瀏覽器發送請求到django的wsgi,wsgi接收到這個請求,然後封裝成request對象,request對象走url路由匹配,路由匹配成功後走視圖函數,執行視圖函數,在執行模板(template),把模板讀取出來,通過models在資料庫中拿對應的數據,拿到數據後在返回給models,然後在給視圖,拿到模板和數據進行渲染,然後變成http對象給wsgi

情況三:有model和HTML和中間件
瀏覽器發送請求到django的wsgi,wsgi接收到這個請求,然後封裝成request對象,先經過中間件進行處理,request對象走url路由匹配,路由匹配成功後走視圖函數,執行視圖函數,在執行模板(template),把模板讀取出來,通過models在資料庫中拿對應的數據,拿到數據後在返回給models,然後在給視圖,拿到模板和數據進行渲染,然後在經過中間件,封裝成http對象給wsgi

中間件

中間件是Django請求/響應處理的鉤子框架。這是一個輕量級的低級“插件”系統,用於在全球範圍內改變Django的輸入或輸出。

每個中間件組件都負責完成一些特定的功能。

1. process_request(self,request)

執行時間: 在視圖函數和路由匹配之前執行

參數: request ,request請求對象和視圖函數是同一個

返回值:
  None  正常流程
  Httpresponse :按照app的註冊順序執行,當其中某一個中間件有Httpresponse返回值時,當前中間件之後的中間件的process_request方法 , 路由匹配 , 視圖函數都不執行,直接執行當前中間件的process_response(響應)方法,倒序執行之前的response的方法,最終返回給瀏覽
        
        
# 示例
#  view.py視圖函數
from django.shortcuts import render,HttpResponse
def index(request):
    print('request index')
    return HttpResponse('ok')


#  mymiddleware.py
都沒有返回值的情況:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,render
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print('MD1 process_request')

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')
        
        
結果: MD1 process_request
      MD2 process_request
        
        
MD1有返回值的情況:       
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,render
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print('MD1 process_request')
        return HttpResponse('MD1 MiddlewareMixin')

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')      
        
結果:MD1 process_request
    
    
    
都有返回值的情況:       
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,render
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print('MD1 process_request')
        return HttpResponse('MD1 MiddlewareMixin')

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')  
        return HttpResponse('MD2 MiddlewareMixin')
        
結果:
    MD1 process_request
    

2.process_response(self,request,response)

執行時間: 在視圖函數之後執行

參數:
  request:  請求對象和視圖函數是同一個
  response: 視圖函數或process_request方法返回的response對象

執行的順序 :按照中間件的註冊順序 -- 倒序執行

返回值:
    Httpresponse : 必須返回視圖函數的response對象或者返回HttpResponse('內容') --> 內容會取代視圖函數的返回內容
    
# 示例
# view.py視圖函數
from django.shortcuts import render,HttpResponse
def index(request):
    print('request index')
    return HttpResponse('ok')   
    

# mymiddleware.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,render

class MD1(MiddlewareMixin):
    def process_request(self,request):
        print('MD1 process_request')

    def process_response(self,request,response):
        print('MD1 process_response')
        return response


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')

    def process_response(self,request,response):
        print('MD2 process_response')
        return response
        # return HttpResponse('ojbk')  當返回一個HttpResponse,這個內容會取代視圖函數index中的return HttpResponse('ok') ,顯示的頁面內容為:ojbk
結果:
    MD1 process_request
    MD2 process_request
    request index
    MD2 process_response
    MD1 process_response
    #顯示的頁面內容為:ok

3.process_view(self, request, view_func, view_args, view_kwargs)

先執行process_request,在執行路由匹配,在執行process_view,在執行視圖

執行時間: 在視圖函數之前,路由匹配之後執行

參數

    request : 請求對象和視圖函數是同一個
    view_func : 視圖函數
    view_args : 傳遞給視圖函數的位置參數 -- 分組的參數
    view_kwargs : 傳遞給視圖函數的關鍵字參數 -- 命名分組的參數

執行順序:  按照中間件的註冊順序,順序執行

返回值

    None : 正常流程
    Httpresponse : 返回HttpResponse,當前中間件之後的中間件的process_view方法,視圖函數都不執行,直接執行最後一個中間件的process_response方法,倒序執行之前的process_response方法. 最終返回給瀏覽器
        
# 示例
#  view.py視圖函數
from django.shortcuts import render,HttpResponse
def index(request):
    print('request index')
    return HttpResponse('ok')   


#  mymiddleware.py
process_view沒有返回值的情況
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,render
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print('MD1 process_request')
       
    def process_response(self,request,response):
        print('MD1 process_response')
        return response
   
    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD1 process_view')


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')

    def process_response(self,request,response):
        print('MD2 process_response')
        return response

    def process_v

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、線程安全 線程安全的概念:當多個線程訪問某一個類(對象或方法)時。這個類始終都能表現出正確的行為那麼這個類(對象或方法)就是線程安全的。 synchronized:可以在任何對象及方法上加鎖,而加鎖的這段代碼稱為“互斥區”或“臨界區” 示例:【com.study.base.thread.a_sy ...
  • 二叉查找樹是將一組無序的數據構建成一顆有序數據的樹,其設計思想與二分法類似。很好的提高了海量數據查找效率,使得由從頭遍歷到尾的方式轉為二分查找的方式,時間複雜度從O(n)降低為O(log(n))。 ...
  • 搭建 vue cli 腳手架 1. 安裝 git 2. 安裝 node 並配置環境變數,使用 zip 版本 3. 使用淘寶鏡像 4. 安裝 node 模塊 cnpm 5. 全局安裝 vue cli 6. 使用 webpack 骨架初始化應用 ,就像 maven 骨架一樣 7. 運行項目 引入 Ele ...
  • 描述:Spring框架中,@Resource註解報錯,在書寫時沒有自動提示 解決方法:因為maven配置文件的pom.xml文件中缺少javax.annotation的依賴,在pom.項目路中加入依賴即可 <!-- Javax Annotation --> <dependency> <groupId ...
  • 0. 為什麼人人都討厭寫單測 在之前的關於 "swagger" 文章里提到過, 程式員最討厭的兩件事,一件是別人不寫文檔,另一件就是自己寫文檔。這裡如果把文檔換成單元測試也同樣成立。 每個開發人員都明白單元測試的作用,也都知道代碼覆蓋率越高越好。高覆蓋率的代碼,相對來說出現 BUG 的概率就越低,在 ...
  • 定義:我們如何把現實中大量而複雜的問題以 特定的數據類型 和 特定的存儲結構 保存到主記憶體器中(記憶體),以及在此基礎上為實現某個功能(比如查找某個元素,刪除某個元素,對所有元素進行排序)而執行的相應操作,這個相應的操作也叫演算法 數據結構 = 個體 + 個體的關係 演算法 = 對存儲結構的操作 演算法:解 ...
  • 以下代碼可對結構體數組中的元素進行排序,也差不多算是一個小小的模板了吧 運行結果: 也可以這樣 對優先隊列的應用,POJ2431是一個很好的題目,此題用了優先隊列+貪心 Expedition Time Limit: 1000MS Memory Limit: 65536K Total Submissi ...
  • 開發環境: Windows操作系統開發工具:MyEclipse/Eclipse + JDK+ Tomcat + MySQL 資料庫項目簡介: 一款由jsp+ssh+mysql實現的CRM客戶關係管理系統,其中struts版本是struts2,系統實現了CRM客戶關係系統的基本功能,主要有信息管理(包 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...