框架

第十三章: Django 框架


1. HTTP認識

http工做原理

HTTP 請求/響應的步驟:php

  1. 客戶端鏈接到Web服務器css

    一個HTTP客戶端,一般是瀏覽器,與Web服務器的HTTP端口(默認爲80)創建一個TCP套接字鏈接。例如,http://www.luffycity.com。html

  2. 發送HTTP請求前端

    經過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成。python

  3. 服務器接受請求並返回HTTP響應mysql

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

  4. 釋放鏈接TCP鏈接正則表達式

    若connection 模式爲close,則服務器主動關閉TCP鏈接,客戶端被動關閉鏈接,釋放TCP鏈接;若connection 模式爲keepalive,則該鏈接會保持一段時間,在該時間內能夠繼續接收請求;sql

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

    客戶端瀏覽器首先解析狀態行,查看代表請求是否成功的狀態代碼。而後解析每個響應頭,響應頭告知如下爲若干字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,並在瀏覽器窗口中顯示。

http請求方法

HTTP/1.1協議中共定義了八種方法(也叫「動做」)來以不一樣方式操做指定的資源:

  1. get:

    • 向指定的資源發出「顯示」請求。使用GET方法應該只用在讀取數據,而不該當被用於產生「反作用」的操做中,例如在Web Application中。其中一個緣由是GET可能會被網絡蜘蛛等隨意訪問。
  2. head:

    • 與GET方法同樣,都是向服務器發出指定資源的請求。只不過服務器將不傳回資源的本文部分。它的好處在於,使用這個方法能夠在沒必要傳輸所有內容的狀況下,就能夠獲取其中「關於該資源的信息」(元信息或稱元數據)。
  3. post:

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

      <form action="http://127.0.0.1:8001" method="post"> 默認是get請求
      <input type="text" name="user">
      <input type="password" name="pwd">
      <input type="submit">
      </form>
  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請求錯誤——請求含有詞法錯誤或者沒法被執行
  • 5xx服務器錯誤——服務器在處理某個正確請求時發生錯誤

URL

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

  • 傳送協議。

  • 層級URL標記符號(爲[//],固定不變)

  • 訪問資源須要的憑證信息(可省略)

  • 服務器。(一般爲域名,有時爲IP地址)

  • 端口號。(以數字方式表示,若爲HTTP的默認值「:80」可省略)

  • 路徑。(以「/」字符區別路徑中的每個目錄名稱)

  • 查詢。(GET模式的窗體參數,以「?」字符爲起點,每一個參數以「&」隔開,再以「=」分開參數名稱與數據,一般以UTF8的URL編碼,避開字符衝突的問題)

  • 片斷。以「#」字符爲起點

    以http://www.luffycity.com:80/news/index.html?id=250&page=1 爲例, 其中:
    
    http,是協議;
    www.luffycity.com,是服務器;
    80,是服務器上的默認網絡端口號,默認不顯示;
    /news/index.html,是路徑(URI:直接定位到對應的資源);
    ?id=250&page=1,是查詢

HTTP請求格式(請求協議)

1562922366891

HTTP響應格式(響應協議)

1562922463671

2. WEB框架本質

多線程的web框架

import socket
from threading import Thread

sk = socket.socket()
sk.bind(('127.0.0.1',8008))
sk.listen()

def html(conn):
    with open('demo2.html', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def css(conn):
    with open('test.css', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def js(conn):
    with open('test.js', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def jpg(conn):
    with open('1.png', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def ico(conn):
    with open('jd.ico', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

urlpatterns = [
    ('/',html),('/test.css',css),
    ('/1.png',jpg),('/test.js',js),('/jd.ico',ico),]

while True:
    conn,addr = sk.accept()
    mes = conn.recv(1024).decode('utf-8')
    path = mes.split('\r\n')[0].split(' ')[1]
    print(path)
    conn.send(b'http/1.1 200 ok \r\n\r\n')
    for i in urlpatterns:
        if path == i[0]:
            t = Thread(target=i[1],args=(conn,))
            t.start()
            
# <link rel="icon" href="jd.ico"> 在head標籤中設置ico,(小圖標)

設置動態的web框架

# 在上面的基礎上修改

def html(conn):
    time_tag = str(time.time())
    with open('demo2.html', 'r',encoding='utf-8') as f:
        data = f.read()
    # html中隨便添加一個內容,而後將其替換
    data = data.replace('xxoo',time_tag).encode('utf-8') 
    conn.send(data)
    conn.close()

wsgired 模塊版的web框架

  • wsgiref自己就是個web框架,提供了一些固定的功能(請求和響應信息的封裝,不須要咱們本身寫原生的socket了也不須要我們本身來完成請求信息的提取了,提取起來很方便

  • environ : 是所有加工好的請求信息,加工成了一個字典,經過字典取值的方式就能拿到不少你想要拿到的信息

  • start_response: 幫你封裝響應信息的(響應行和響應頭),注意下面的參數

    import time
    from wsgiref.simple_server import make_server
    
    def html():
        time_tag = str(time.time())
        with open('demo2.html', 'r',encoding='utf-8') as f:
            data = f.read()
        data = data.replace('xxoo',time_tag).encode('utf-8')
        return data
    
    def css():
        with open('rr.css', 'rb') as f:
            data = f.read()
        return data
    
    def js():
        with open('test.js', 'rb') as f:
            data = f.read()
        return data
    
    def jpg():
        with open('1.jpg', 'rb') as f:
            data = f.read()
        return data
    
    def ico():
        with open('jd.ico', 'rb') as f:
            data = f.read()
        return data
    
    urlpatterns = [
        ('/',html),('/rr.css',css),
        ('/1.jpg',jpg),('/test.js',js),('/jd.ico',ico),]
    
    def application(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')])
        path = environ['PATH_INFO']   # 拿到每一個請求
        print(path)
        for i in  urlpatterns:
            if path == i[0]:
                ret = i[1]()
                break
        else:
            ret = b'404 not found!!!!'
        return [ret]
    
    httpd = make_server('127.0.0.1', 8080, application)
    
    print('Serving HTTP on port 8080...')
    httpd.serve_forever()

jinja2 版的框架

# HTML文件
<h1>{{userinfo}}</h1>
<ul>
    {% for k,v in userinfo.items()%}
        <li>{{k}}--{{v}}</li>
    {% endfor %}
</ul>

# py文件 在上面基礎上修改
from jinja2 import Template
def html():
    user = showdata()
    with open('demo2.html', 'r',encoding='utf-8') as f:
        data = f.read()
    tem = Template(data)
    data = tem.render({'userinfo':user})
    data = data.encode('utf-8')
    return data

3. MVC 和 MTV框架

  1. 所謂的mvc就是把web應用分爲模型(M),控制器(C),和視圖(V),他們之間以一種插件式的,鬆耦合的方式鏈接在一塊兒的,模型負責業務對象與數據庫的映射(ORM),視圖負責與用戶的交互,控制器接收用戶的輸入調用模型和視圖完成用戶的請求

  2. Django的MTV模式本質上和mvc是同樣的,也是爲了各組件保持鬆耦合的關係,只是定義上有些不一樣,Django的MTV分別是值

    • M : 表明模型(Model),負責業務數據和數據庫的映射
    • T : 表明模板(Template),負責如何把頁面展現給用戶(HTML)
    • V : 表明視圖(View),負責業務邏輯,並在適當的時候調用Model和Template.

    除了以上三層外,還須要一個URL分發器,它的做用是將一個URL的頁面請求分發給不一樣的View處理,View在調用相應的Model和Template,響應模式以下

  • 通常是用戶經過瀏覽器向咱們的服務器發起一個請求(request),這個請求回去訪問視圖函數,(若是不涉及到數據調用,那麼這個時候視圖函數返回一個模板也就是一個網頁給用戶),視圖函數調用模型,模型去數據庫查找數據,而後逐級返回,視圖函數把返回的數據填充到模板中空格中,最後返回網頁給用戶。

4. Django下載安裝

  1. 官網地址 : https://www.djangoproject.com/download/
  2. 下載Django: pip3 install django == 1.11.9
  3. 建立一個Django project:
    • Django-admin startproject mysite 建立一個名爲mysite的Django項目
  4. 建立app : python manage.py startapp app的名字
  5. 建立的項目的文件介紹
    • manage.py -- Django項目裏面的工具,經過他能夠調用Django shell和數據庫,啓動關閉項目與項目交互 等,無論你將框架分了幾個文件,必然有一個啓動文件,其實他們自己就是一個文件。
    • settings.py ---- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。
    • urls.py ----- 負責把URL模式映射到應用程序。
    • wsgi.py ---- runserver命令就使用wsgiref模塊作簡單的web server,後面會看到renserver命令,全部與 socket相關的內容都在這個文件裏面了,目前不須要關注它。
  6. 運行項目
    • python manage.py runserver 127.0.0.1:8080 #此時已經能夠啓動django項目了,只不過什麼邏輯也沒有
    • 經過指令運行項目的時候,能夠不寫ip地址,若是不寫,默認是127.0.0.1
      • python manage.py runserver 8080
    • 若是連端口都不寫,默認是8000端口
      • python manage.py runserver

5. 寫項目

1 建立項目  first_pro 
2 建立app  app01 
作一個登陸頁面的web項目,瀏覽器輸入一個網址獲得一個web頁面
用戶:  http:127.0.0.1:8001/login/
            
1 urls.py     
    from django.conf.urls import url    
    from django.contrib import admin    
    from app01 import views
    urlpatterns = [        # url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),  #配置路徑,r'^/index/',這個前置導航斜槓不須要添加.
    ]
   # urls.py裏面須要注意的問題
        url(r'^index/', views.index),  第一個參數:路徑正則字符串  第二個參數:對應的視圖函數
            
2 寫邏輯視圖(Views)
    from django.shortcuts import render,HttpResponse
    # Create your views here.
    def index(request):
        print(request.method)    # 'POST' 'GET'
        if request.method == 'GET':
            return render(request,'login.html')
        else:            
            username = request.POST.get('username')            
            password = request.POST.get('password')
            if username == 'xin' and password == '123':
                return HttpResponse('登陸成功!')
            else:
                return HttpResponse('登陸失敗!')
            
3 建立html文件(Template文件下)    
    在templates文件夾中建立一個login.html文件
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Bootstrap 101 Template</title>
    </head>
    <body>
    <form action="/login/" method="post">
        姓名:<input type="text" name="username">
        密碼:<input type="password" name="password">
        <input type="submit">
    </form>
    </body>
    </html>

4. views.py
    from django.shortcuts import render,HttpResponse
    # Create your views here.
    def login(request):
        if request.method == 'GET':
            return render(request,'login.html')
        else:
            name = request.POST.get('username')
            ped = request.POST.get('password')
            if name== 'xin' and ped == '666':
                return HttpResponse('成功')
            else:
                return HttpResponse('失敗')

6. URL路由系統

6.1 URL配置

  • 基本格式

    from django.conf.urls import url
    #循環urlpatterns,找到對應的函數執行,匹配上一個路徑就找到對應的函數執行,就再也不往下循環了,並給函數傳一個參數request,和wsgiref的environ相似,就是請求信息的全部內容
    urlpatterns = [
         url(正則表達式, views視圖函數,參數,別名),
    ]
  • 參數說明

    • 正則表達式: 一個正則表達式字符串
    • views視圖函數: 一個可調用對象,一般爲一個視圖函數或一個指定函數路徑的字符串
    • 參數: 可選的要傳給視圖函數的默認參數(字典形式)
    • 別名: 一個可選的name參數

6.2 正則表達式詳解

  • 基本配置

    urls.py:
        from django.conf.urls import url
        from django.contrib import admin
        from app02 import views
    
        urlpatterns = [
            url(r'^books/(\d{4})/$', views.books), # 匹配年
            url(r'^books/(\d{4})/(\d{1,2})/', views.books), # 匹配年月
        ]
    
    views.py:
        # 第一個參數必須是request,後面跟的三個參數是對應着上面分組正則匹配的每一個參數的
        def books(request,year,month):
            return HttpResponse(year+month)
  • 補充說明:

    # 是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項
    APPEND_SLASH=True

6.3 分組命名匹配

from django.conf.urls import url

from app01 import views

urlpatterns = [
   url(r'^articles/(\d{4})/$', views.year_archive), # year_archive(request,n),小括號爲分組,有分組,那麼這個分組獲得的用戶輸入的內容,就會做爲對應函數的位置參數傳進去,別忘了形參要寫兩個了
    
    url(r'^articles/(?P<year>\d{4})/$', views.year_archive),#某年的,(?P<year>[0-9]{4})這是命名參數,那麼函數year_archive(request,year),形參名稱必須是year這個名字。並且注意若是你這個正則後面沒有寫$符號,即使是輸入了月份路徑,也會被它攔截下拉,由於它的正則也能匹配上
    
    url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),#某年某月的
    
    url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', views.article_detail), #某年某月某日的
]
  • 視圖函數中指定默認值

    # urls.py中
    from django.conf.urls import url
    
    from app01 import views
    
    urlpatterns = [
        url(r'^blog/$', views.page),
        url(r'^blog/page(?P<num>\d+)/$', views.page),
    ]
    
    # views.py中,能夠爲num指定默認值
    def page(request, num="1"):
        pass

6.4 URL路由分發 -- include

# 項目文件夾下的urls.py文件中的url寫法:
    from django.conf.urls import url,include
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        #首頁
        url(r'^$', views.base),
        url(r'^app01/', include('app01.urls')),
        url(r'^app02/', include('app02.urls')),
    ]
    
# app01下urls.py內容寫法
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^$', views.app01base),
    ]
    
# app02下urls.py內容寫法   
    from django.conf.urls import url
    from django.contrib import admin
    from app02 import views
    urlpatterns = [
        url(r'^$', views.app02base),
    ]

7. 視圖函數

7.1 請求相關的屬性方法(request-->HttpRequest對象)

def index(request):   # http相關請求信息---封裝--HttpRequest對象

    if request.method == 'GET':
        print(request.body)   # 獲取post請求提交過來的原始數據
        print(request.GET)    # 獲取GET請求提交的數據
        # print(request.META) # 請求頭相關信息,就是一個大字典
        print(request.path)      # /index/ 路徑
        print(request.path_info) # /index/ 路徑
        print(request.get_full_path())  # /index/?username=dazhuang&password=123
        
        return render(request,'index.html')
    else:
        print(request.body)  # b'username=dazhuang'
        print(request.POST)  # 獲取POST請求提交的數據
        return HttpResponse('男賓三位,拿好手牌!')

7.2 響應相關方法

HttpResponse  --- 回覆字符串的時候來使用
render --- 回覆一個html頁面的時候使用
redirect -- 重定向

示例:
# views.py
    from django.shortcuts import render,HttpResponse,redirect
    def login(request):
        if request.method == 'GET':
            return render(request,'login.html')
        else:
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'taibai' and password == 'dsb':
                return  redirect('/home/')    # 重定向
            else:
                return HttpResponse('滾犢子,趕忙去充錢!!!')

    def home(request):
        return render(request,'home.html')
    
# urls.py
    urlpatterns = [
        url(r'^test/', views.test),
        url(r'^home/', views.home),
    ]

7.3 301和302的區別

1)301和302的區別。

  301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址能夠從響應的Location首部中獲取
  (用戶看到的效果就是他輸入的地址A瞬間變成了另外一個地址B)——這是它們的共同點。

  他們的不一樣在於。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換爲重定向以後的網址;

  302表示舊地址A的資源還在(仍然能夠訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。 SEO302好於301

 

2)重定向緣由:
(1)網站調整(如改變網頁目錄結構);
(2)網頁被移到一個新地址;
(3)網頁擴展名改變(如應用須要把.php改爲.Html或.shtml)。
        這種狀況下,若是不作重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶獲得一個404頁面錯誤信息,訪問流量白白喪失;再者某些註冊了多個域名的
    網站,也須要經過重定向讓訪問這些域名的用戶自動跳轉到主站點等。

臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來講是沒什麼區別的,它主要面向的是搜索引擎的機器人。

  • A頁面臨時重定向到B頁面,那搜索引擎收錄的就是A頁面。
  • A頁面永久重定向到B頁面,那搜索引擎收錄的就是B頁面。

7.4 CBV和FBV

  1. FBV(function based views) : 就是在視圖裏使用函數處理

    def home(request):
        print('home!!!')
        return render(request,'home.html')
  2. CBV(class based views) : 在視圖裏使用類處理請求

    views.py
        from django.views import View
        class LoginView(View):
            # 經過請求方法找到本身寫的視圖類裏面對應的方法
            def get(self,request):
    
                return render(request,'login2.html')
            def post(self,request):
                username = request.POST.get('uname')
                password = request.POST.get('pwd')
                print(username,password)
    
                return HttpResponse('登陸成功!')
    
    urls.py
     url(r'^login2/', views.LoginView.as_view()),
  3. FBV加裝飾器

    def wrapper(f):
        def inner(*args,**kwargs):
            print('請求以前')
            ret = f(*args,**kwargs)
            print('請求以後')
            return ret
        return inner
    
    @wrapper
    def home(request):
        print('home!!!')
        return render(request,'home.html')
  4. CBV加裝飾器

    from django.views import View
    from django.utils.decorators import method_decorator
    
    def wrapper(f):
        def inner(*args,**kwargs):
            print('請求以前')
            ret = f(*args,**kwargs)
            print('請求以後')
            return ret
        return inner
    
    @method_decorator(n1,name='get')   # 方式三
    class LoginView(View):
    
        @method_decorator(n1)  # 方式2 給全部方法加裝飾器
        def dispatch(self, request, *args, **kwargs):
            # print('請求來啦')
            ret = super().dispatch(request, *args, **kwargs)
            # print('到點了,走人了')
            return ret
    
        @method_decorator(n1)      # 方式1
        def get(self,request):
            print('get方法執行了')
            return render(request,'login2.html')
    
        def post(self,request):
            username = request.POST.get('uname')
            password = request.POST.get('pwd')
            return HttpResponse('登陸成功!')
  5. CBV的dispatch方法

    from django.views import View
    class LoginView(View):
        # GET 
        def dispatch(self, request, *args, **kwargs):
            print('請求來啦')
            ret = super().dispatch(request, *args, **kwargs)
            print('到點了,走人了')
            return ret
        def get(self,request):
            print('get方法執行了')
            return render(request,'login2.html')
        def post(self,request):
            username = request.POST.get('uname')
            password = request.POST.get('pwd')
            print(username,password)
            return HttpResponse('登陸成功!')

8. 模板系統

8.1 語法

  • 變量相關的用: {{ 變量名 }}
  • 邏輯相關的用: {% 邏輯 %}

8.2 變量

# 示例
html代碼:
    <p>{{ num }}</p>
    <p>{{ name }}</p>
    <p>{{ name_list.2 }}</p>  # 經過 .索引 來取值
    <p>{{ d1.age }}</p>  # 經過 .鍵 取值
    <p>{{ a.kind }}</p>
    <p>{{ a.eat }}</p>  # 調用類中方法
    
views.py代碼
    def index(request):
        num = 100
        name = 'shige'
        name_list = ['大壯','小壯','壯壯']
        d1 = {'name':'大壯','age':73,'hobby':'xuefei+xiangxi'}

        class Animal:
            def __init__(self):
                self.kind = 'dog'
            def eat(self):
                return 'shi'
        a = Animal()

        return render(request,'index.html',{'num':num,'name':name,'namelist':name_list,'d1':d1,'a':a})
        # return render(request,'index.html',locals()) 
        locals() 獲取函數內部全部變量的值,並加工成{'變量名':'變量值'....}這樣一個字典

8.3 過濾器

  1. default : 若是一個變量是false或者爲空,使用給定的默認值.不然使用變量的值

    {{ value|default:"nothing"}}
  2. length : 返回值的長度,做用於字符串和列表。

    mes = 'I love you three thousand times'
    {{ mes|length }}  # 31
  3. filesizeformat : 將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)

    filesize = 234352452
    {{ filesize|filesizeformat }} # 223.5 MB
  4. slice : 切片,若是 value="hello world",還有其餘可切片的數據類型

    {{value|slice:"2:-1"}}
  5. date : 格式化,若是 value=datetime.now()

    {{ value|date:"Y-m-d H:i:s"}}
  6. safe : 將字符串識別成標籤

    val = '<a href="http://www.baidu.com">百度</a>'
    ret = "<script>alert('123')</script>"
    
    {{ val|safe }} # 生成a標籤的樣式
    {{ ret|safe }} # 有js的樣式
  7. truncatechars : 若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。

    mes = 'I love you three thousand times'
    {{ value|truncatechars:10}} #注意:最後那三個省略號也是9個字符裏面的,也就是這個9截斷出來的是6個字符+3個省略號,獲得結果 : I love ... (空格一算一個字符)
  8. truncatewords : 在必定數量的字後截斷字符串,是截多少個單詞。

    mes = 'I love you three thousand times'
    {{ value|truncatewords:3}} # I love you ...
  9. cut : 移除全部的與給出變量相同的字符串

    mes = 'I love you three thousand times'
    {{ value|cut:' ' }} # Iloveyouthreethousandtimes
  10. join : 使用字符串鏈接列表,相似於python中str.join(list)

    lis = [11,22,33]
    {{ lis|join:'-' }} # 11-22-33

8.4 標籤Tags

  1. for標籤

    • 遍歷每個元素: 寫個for,而後 tab鍵自動生成for循環的結構

      dic = {'name':'alex','age':77}
      
      {% for k,v in dic.items %}  # 循環字典
          <li>{{ k }} - {{ v }}</li>
      {% endfor %}
      # name - alex
      # age - 77
    • for循環的其餘方法

      forloop.counter      當前循環的索引值(從1開始),forloop是循環器,經過點來使用功能
      forloop.counter0     當前循環的索引值(從0開始)
      forloop.revcounter   當前循環的倒序索引值(從1開始)
      forloop.revcounter0  當前循環的倒序索引值(從0開始)
      forloop.first        當前循環是否是第一次循環(布爾值)
      forloop.last         當前循環是否是最後一次循環(布爾值)
      forloop.parentloop   本層循環的外層循環的對象,再經過上面的幾個屬性來顯示外層循環的計數等
      forloop.parentloop.counter
      {#  {% for key,value in d1.items %}#}
          {#    {{ forloop.counter }}#}
          {#      <li>{{ key }} -- {{ value }}</li>#}
          {#  {% endfor %}#}
      
          {#    {% for key,value in d1.items %}#}
          {#    {{ forloop.counter0 }}#}
          {#      <li>{{ key }} -- {{ value }}</li>#}
          {#  {% endfor %}#}
      
          {#    {% for key,value in d1.items %}#}
          {#      {{ forloop.revcounter }}#}
          {#        <li>{{ key }} -- {{ value }}</li>#}
          {#    {% endfor %}#}
      
          {#      {% for key,value in d1.items %}#}
          {#        {{ forloop.revcounter0 }}#}
          {#          <li>{{ key }} -- {{ value }}</li>#}
          {#      {% endfor %}#}
      
          {#      {% for key,value in d1.items %}#}
          {#        {{ forloop.first }}#}
          {#          <li>{{ key }} -- {{ value }}</li>#}
          {#      {% endfor %}#}
      
      
          <!-- forloop.parentloop示例 -->
          {#<ul>#}
          {#    {% for dd2 in d2 %}#}
          {#      <li>#}
          {#        {% for ddd2 in dd2 %}#}
          {#          {{ forloop.parentloop.counter }}#}
          {#          {{ forloop.counter }}#}
          {#          <a href="">{{ ddd2 }}</a>#}
          {#        {% endfor %}#}
          {##}
          {#      </li>#}
          {#  {% endfor %}#}
          {#</ul>#}
      
          <!-- empty示例 -->
          {#<ul>#}
          {#   {% for foo in d3 %}#}
          {#       <li>{{ foo }}</li>#}
          {#   {% empty %}#}
          {#     <li>查詢的內容啥也沒有</li>#}
          {#  {% endfor %}#}
          {##}
          {#</ul>#}
  2. if 標籤

    {% if num > 100 %}
        <p>excellent</p>
    {% elif num == 100 %}
        <p>beautiful</p>
    {% else %}
        <p>nice</p>
    {% endif %}
    
    1. Django的模板語言不支持連續判斷,即不支持如下寫法:
    {% if a > b > c %}
    ...
    {% endif %}
    2. Django的模板語言中屬性的優先級大於方法(瞭解)
    def xx(request):
        d = {"a": 1, "b": 2, "c": 3, "items": "100"}
        return render(request, "xx.html", {"data": d})
    • if語句支持: and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格。
  3. with標籤

    • 使用一個簡單地名字緩存一個複雜的變量,多用於給一個複雜的變量起別名,當你須要使用一個「昂貴的」方法(好比訪問數據庫)不少次的時候是很是有用的,注意等號不要加空格

      # 兩種方式
      {% with total=business.employees.count %}
          {{ total }} <!--只能在with語句體內用-->
      {% endwith %}
      
      {% with business.employees.count as total %}
          {{ total }}
      {% endwith %}
  4. csrf_token

    安全認證機制  
     咱們以post方式提交表單的時候,會報錯,還記得咱們在settings裏面的中間件配置裏面把一個csrf的防護機制給註銷了啊,自己不該該註銷的,而是應該學會怎麼使用它,而且不讓本身的操做被forbiden,經過這個東西就能搞定。
    
     這個標籤用於跨站請求僞造保護,
    
     在頁面的form表單裏面(注意是在form表單裏面)任何位置寫上{% csrf_token %},這個東西模板渲染的時候替換成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隱藏的,這個標籤的值是個隨機字符串,提交的時候,這個東西也被提交了,首先這個東西是咱們後端渲染的時候給頁面加上的,那麼當你經過我給你的form表單提交數據的時候,你帶着這個內容我就認識你,不帶着,我就禁止你,由於後臺咱們django也存着這個東西,和你這個值相同的一個值,能夠作對應驗證是否是我給你的token,存儲這個值的東西咱們後面再學,你先知道一下就好了,就像一個咱們後臺給這個用戶的一個通行證,若是你用戶沒有按照我給你的這個正常的頁面來post提交表單數據,或者說你沒有先去請求我這個登錄頁面,而是直接模擬請求來提交數據,那麼我就能知道,你這個請求是非法的,反爬蟲或者惡意攻擊個人網站。
  5. 模板繼承

    {% extends "base.html" %}  # 寫在開始
    
    鉤子:{% block title %}
         xxx
     {% endblock %}
    鉤子:{% block title %}
         xxx
     {% endblock title %}
    
    鉤子:{% block title %}
         {{ block.super }}  # 顯示繼承模板的內容
         xxx
  6. 組件

    {% include 'navbar.html' %}   # 引用組件的html文件
    
    組件是提供某一完整功能的模塊,如:編輯器組件,QQ空間提供的關注組件 等。
    
    而插件更傾向封閉某一功能方法的函數。
    
    這二者的區別在 Javascript 裏區別很小,組件這個名詞用得很少,通常統稱插件。

8.5 自定義標籤和過濾器

  1. 自定義過濾器

    • 在settings中的 INSTALL_APPS 配置當前的app,否則Django沒法找到自定義的過濾器

    • app應用文件夾中建立一個templatetags文件件,必須是這個名字

    • templatetags文件夾中建立一個 xx.py 文件,文件名字隨便起

    • 在新建的 xx.py 文件中建立自定義過濾器

      from Django import template
      
      register = template.Library() # register固定名字,註冊器
      
      @register.filter
      def oo(v1):    # 不帶參數的過濾器,第一個參數v1是views視圖函數中傳過來的
         s = v1 + 'xxoo'
         return s
      
      @register.filter
      def oo(v1,v2):  # 帶參數的過濾器
         s = v1 + v2
         return s
    • 使用html文件中的數據

      {% load xx %}
      {{ values|oo }} -- 無參數
      {{ values|oo:'asdf' }} -- 有參數
    • 參數最多兩個

  2. 自定義標籤

    • 在settings中的 INSTALL_APPS 配置當前的app,否則Django沒法找到自定義的過濾器

    • app應用文件夾中建立一個templatetags文件件,必須是這個名字

    • templatetags文件夾中建立一個 xx.py 文件,文件名字隨便起

    • 在新建的 xx.py 文件中建立自定義過濾器

      from Django import template
      
      register = template.Library() # register固定名字,註冊器
      
      @register.simple_tag
      def mytag(v1,v2,v3):   # 第一個參數v1是views視圖函數中傳過來的
          s = v1 + v2 + v3
          return s
    • 使用

      {% load xx %}
      {% mytag s1 '啦啦' '呵呵' %}
  3. inclusion_tag : 多用於返回html代碼片斷

    # views.py
    def index(request):
        lis = [11,22,33,44,55,66]
        return render(request,'index.html',{'lis':lis})
    
    # index.html
    {% load one %}
    {% func lis %}
    
    # one.py
    from django import template
    register = template.Library()
    @register.inclusion_tag('test.html') # 將test.html裏面的內容用下面函數的返回值渲染,而後做爲一個組件同樣,加載到使用這個函數的HTML裏面
    def func(v1):
        return {'data':v1}  # v1 是傳過來的lis列表
    
    # test.html
    <ul>
        {% for d in data %}
            <li>{{ d }}</li>
        {% endfor %}
    </ul>
    
    流程: 先執行index函數,將lis傳給index.html,index.html中將lis做爲func的參數傳進去,v1=lis,在one.py中,將v1傳給test.html進行渲染,最後將渲染的結果返回給index.html,在頁面顯示出來

8.6 靜態文件

  • js,css,img 等都叫作靜態文件,那麼在關於jango中靜態文件的配置,咱們就須要在settings配置文件中寫上下面內容

    # 在項目目錄下建立一個文件用來存放靜態文件,一般名稱爲 : static
    
    STATIC_URL = '/static/'  # 別名
    
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR,'static'), # 注意別忘了寫逗號,第二個參數就是項目中你存放靜態文件的文件夾名稱
    ]
  • 目錄 : 別名也是一種安全機制,瀏覽器上經過調試臺你能看到的是別名的名字,這樣別人就不知道你靜態文件的名字了,否則別人就能經過這個文件夾路徑進行攻擊

  • 前端頁面引入靜態文件的寫法,由於別名也可能會修改,因此使用路徑的時候經過load static來找別名,經過別名映射路徑的方式來獲取靜態文件

    1563443109847

  • {% static %}

    {% load static %}
    <img src="{% static "images/hi.jpg" %}" alt="Hi!" />
  • 引用JS文件時使用

    {% load static %}
    <script src="{% static "mytest.js" %}"></script>
  • 某個文件多處被用到的能夠存爲一個變量

    {% load static %}
    {% static "/images/hi.jpg" as myphoto %}
    <img src="{{ myphoto }}"></img>
  • 注意:

    • 一個html文件中寫相對路徑是須要注意一個問題

      <form action="/login/"></form>
      <img src="/static/1.jpg" alt="">
      等標籤須要寫路徑的地方,若是寫的是相對路徑,那麼前置的/這個斜槓必須寫上,否則這個請求會拼接當前網頁的路徑來發送請求,就不能匹配咱們的後端路徑了

9. 單表操做

1. ORM簡介

  • ORM是 對象--關係--映射 的簡稱.實現了數據模型與數據庫的解耦,即數據庫的設計不須要依賴特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫

  • 類對象 --> sql --> pymysql --> mysql服務端 --> 磁盤,orm其實就是將類對象的語法翻譯成sql語句的一個引擎

    1563450677894

2. 建表操做

在python中orm的對應關係有三種:

類     ---------->表

類對象 ---------->行(記錄)

類屬性 ---------->表的字段(重點
  1. 建立表

    # app 應用下的 models.py 文件中寫
    from django.db import models
    class UserInfo(models.Model):  # UserInfo 爲表名
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=10)
        age = models.IntegerField()
        current_date = models.DateField()
  2. 更多字段和參數

    • 字段

      <1> CharField
              字符串字段, 用於較短的字符串.
              CharField 要求必須有一個參數 maxlength, 用於從數據庫層和Django校驗層限制該字段所容許的最大字符數.
      
      <2> IntegerField
             用於保存一個整數.
      
      <3> DecimalField
              一個浮點數. 必須 提供兩個參數:
      
      <4> AutoField
              一個 IntegerField, 添加記錄時它會自動增加. 你一般不須要直接使用這個字段;
              自定義一個主鍵:my_id=models.AutoField(primary_key=True)
              若是你不指定主鍵的話,系統會自動添加一個主鍵字段到你的 model.
    • 參數

      (1)null
      
      若是爲True,Django 將用NULL 來在數據庫中存儲空值。 默認值是 False.
      
      (1)blank
      
      若是爲True,該字段容許不填。默認爲False。
      要注意,這與 null 不一樣。null純粹是數據庫範疇的,而 blank 是數據驗證範疇的。
      若是一個字段的blank=True,表單的驗證將容許該字段是空值。若是字段的blank=False,該字段就是必填的。
      
      (2)default
      
      字段的默認值。能夠是一個值或者可調用對象。若是可調用 ,每有新對象被建立它都會被調用,若是你的字段沒有設置能夠爲空,那麼未來若是咱們後添加一個字段,這個字段就要給一個default值
      
      (3)primary_key
      
      若是爲True,那麼這個字段就是模型的主鍵。若是你沒有指定任何一個字段的primary_key=True,
      Django 就會自動添加一個IntegerField字段作爲主鍵,因此除非你想覆蓋默認的主鍵行爲,
      不然不必設置任何一個字段的primary_key=True。
      
      (4)unique
      
      若是該值設置爲 True, 這個數據字段的值在整張表中必須是惟一的
      
      (5)choices
      由二元組組成的一個可迭代對象(例如,列表或元組),用來給字段提供選擇項。 若是設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,<br>並且這個選擇框的選項就是choices 中的選項。
      (6)db_index
        若是db_index=True 則表明着爲此字段設置數據庫索引。
      
      
      DatetimeField、DateField、TimeField這個三個時間字段,均可以設置以下屬性。
      
      (7)auto_now_add
          配置auto_now_add=True,建立數據記錄的時候會把當前時間添加到數據庫。
      
      (8)auto_now
          配置上auto_now=True,每次更新數據記錄的時候會更新該字段,標識這條記錄最後一次的修改時間。
  3. settings配置

    • 若想將模型轉爲mysql數據庫中的表,須要在 settings.py 中配置:

      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',
              'NAME':'庫名',        # 要鏈接的數據庫,鏈接前須要建立好
              'USER':'root',     # 鏈接數據庫的用戶名
              'PASSWORD':'',     # 鏈接數據庫的密碼
              'HOST':'127.0.0.1',    # 鏈接主機,默認本級
              'PORT':3306 ,        #  端口 默認3306
          }
      }
    • 項目文件夾下的 init.py文件中,寫下面兩句

      import pymysql
      pymysql.install_as_MySQLdb()
    • 執行數據庫同步指令

      python manage.py makemigrations  # 生成記錄,每次修改了models裏面的內容或者添加了新的app,新的app裏面寫了models裏面的內容,都要執行這兩條
      
      python manage.py migrate     # 執行上面這個語句的記錄來建立表,生成的表名字前面會自帶應用的名字,例如:你的book表在mysql裏面叫作app01_book表

3. 增長數據

  • model.py :

    from django.db import models
    
    class Data(models.Model):
        name = models.CharField(max_length=10)
        age = models.IntegerField()
        current_data = models.DateField()
    
        def __str__(self):
             return self.name
  1. 建立方式一:

    from app import models
    student_obj = models.Data(
        name = 'alex',
        age = 73,
        current_data= '2008-08-08'
    )
    student_obj.save()
  2. 方式二(經常使用此建立)

    from app import models
    new_obj = models.Data.objects.create(
        name = 'wusir',
        age = 83,
        current_data= '2008-08-15',
    )
    
    print(new_obj)   # Data object --> model對象
    print(new_obj.name,new_obj.age)  # .屬性  能夠獲取對應字段的數據
  3. 方式三:

    from app import models
    lis = []
    for i in range(10):
        obj = models.Data(
            name = 'xin',
            age = 18,
            current_data= '2010-10-10'
        )
        lis.append(obj)
        models.Data.objects.bulk_create(lis)   # 批量插入,速度快
  4. 建立方式四: update_or_create 有就更新,沒有就建立

    from app import models
    models.Data.objects.update_or_create(
        name = 'taibai',   # 有就更新
        defaults={'age':89,'current_data':'2011-11-11'}
    
        name = 'xuefei',   # 沒有就建立
        defaults={'age':18,'current_data':'2000-08-08'}
    )

4. 查詢數據

1. 簡單查詢

# all() 查詢全部的數據,返回的是queryset集合
    all_objs = models.Data.objects.all()
    print(all_objs)
    for i in all_objs:
        print(i.name)   # 拿到每個名字

# 條件查詢: filter()方法, 返回的也是queryset集合,查詢不到內容不會報錯,返回一個<QuerySet []>空的queryset
    objs = models.Data.objects.filter(id=15)
    print(objs)

    objs = models.Data.objects.filter(id=1,name='alex').update(name='eva',age=20)
    print(objs)

    打散的形式傳參
    objs = models.Data.objects.filter(**{'id':15,'name':'xuefei'})
    print(objs)

# 條件查詢 : get()方法,返回的是model對象,並且get方法有且必須只有一個結果
    objs = models.Data.objects.get(id=15)
    print(objs)
    查詢的數據不存在會報錯,獲得的結果有兩個時會報錯

# exclude(**kwargs):排除的意思,包含了與所給篩選條件不匹配的對象,沒有不等於操做, objects控制器和queryset集合均可以調用,返回值是queryset類型.
    ex = models.Data.objects.exclude(name='xin')
    ex = models.Data.objects.all().exclude(name='xin')
    print(ex)

# order_by(): queryset類型的數據來調用,查詢結果進行排序,默認是按照id的升序排序的,返回值仍是queryset類型,在字段前面加個 - 號,就是降序排序
    ord = models.Data.objects.order_by('-age','id') # 多條件排序,按照age進行降序,age相同的按照id升序排序
    print(ord)

# reverse() : queryset類型的數據來調用,對查詢結果反向排序,返回值仍是queryset類型
    rev = models.Data.objects.order_by('id').reverse()
    print(rev)

# count() : queryset類型的數據來調用,返回數據庫中匹配查詢(QuerySet)的對象數量。
    con = models.Data.objects.all().count()
    print(con)

# first() : queryset類型的數據來調用,返回第一條記錄,獲得的都是model對象
    obj = models.Data.objects.all().first()
    print(obj)

# last(): queryset類型的數據來調用,返回最後一條記錄,結果爲model對象類型
    obj = models.Data.objects.all().last()
    print(obj)

# exists() : queryset類型的數據來調用,若是QuerySet包含數據,就返回True,不然返回False,空的queryset類型數據也有布爾值True和False,可是通常不用它來判斷數據庫裏面是否是有數據,若是有大量的數據,你用它來判斷,那麼就須要查詢出全部的數據,效率太差了,用count或者exits

# values(*field) : 用的比較多,queryset類型的數據來調用,返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列,model的實例化對象,而是一個可迭代的字典序列,只要是返回的queryset類型,就能夠繼續鏈式調用queryset類型的其餘的查找方法,其餘方法也是同樣的。
# values_list(*field):   它與values()很是類似,它返回的是一個元組序列
    obj = models.Data.objects.all().filter(age=16).values('name','age')
    print(obj)
    obj = models.Data.objects.all().filter(age=16).values_list('name','age')
    print(obj)

# distinct(): values和values_list獲得的queryset類型的數據來調用,從返回結果中剔除重複紀錄,結果仍是queryset
    query = models.Data.objects.all().values('age').distinct()
    print(query)

2. 基於雙下劃線的模糊查詢 

mes = models.Data.objects.filter(price__in=[100,200,300]) # price值等於這三個裏面的任意一個的對象

mes = models.Data.objects.filter(price__gt=100)  # 大於,大於等因而price__gte=100,別寫price>100,這種參數不支持

mes = models.Data.objects.filter(price__lt=100) # 小於

mes = models.Data.objects.filter(price__range=[100,200])  # sql的between and,大於等於100,小於等於200

mes = models.Data.objects.filter(title__contains="python")  #title值中包含python的

mes = models.Data.objects.filter(title__icontains="python") #不區分大小寫

mes = models.Data.objects.filter(title__startswith="py") #以什麼開頭,istartswith  不區分大小寫

all_books = models.Book.objects.filter(pub_date__year=2012) #找2012年的全部書籍

all_books = models.Book.objects.filter(pub_date__year__gt=2012) # 找大於2012年的全部書籍

all_books = models.Book.objects.filter(pub_date__year=2019,pub_date__month=2) #找2019年月份的全部書籍

5. 刪除數據

delete  queryset 和model對象均可以調用

models.Student.objects.get(id=3).delete()  # model對象來調用的delete方法
models.Student.objects.filter(name='Alex').delete()
models.Student.objects.all().delete()  # 刪除全部

6. 更改數據

model對象不能調用更新方法 報錯信息'Student' object has no attribute 'update'
只能queryset調用

models.Student.objects.get(name='alex').update(age=38)  # 報錯
models.Student.objects.filter(name='alex').update(age=38)
相關文章
相關標籤/搜索