Django 框架

Django

HTTP協議:

Socket和Tcp協議關係:

  • socket自己並非協議而是一個調用的接口,socket的出現使咱們更方便的使用tcp協議,如socket的基本接口,listen send recvhtml

HTTP協議概述:

  • HTTP存在應用層的超文本傳輸協議,協議規定了客戶端和服務器之間的通訊標準,採用的是請求和響應模型,客戶端發送一個請求報文,服務端進行響應前端

  • HTTP優勢:無鏈接:請求和響應,無狀態:訪問速度快,通訊標準python

  • 請求格式和響應格式:mysql

1566383310712

1566383326942

HTTP工做原理(重要):

  • 第一步:客戶端鏈接web服務端jquery

    • 客戶端鏈接服務端,會創建一個TCP套接字鏈接,(套接字就是socket,客戶端一般是瀏覽器)git

  • 第二步:發送http請求web

    • 經過TCP套接字,客戶端向web服務端發送一個文本的請求報文,一個請求報文由請求行,請求頭部,和請求數據組成ajax

  • 第三步:服務器接收請求並返回HTTP響應正則表達式

    • 響應就是服務端分析發送過來的請求,經過解析請求定位到資源,服務器將資源寫到tcp套接字中,返回給客戶端

  • 第四步:釋放tcp鏈接

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

  • 第五步:客戶端瀏覽器解析HTML內容

    • 客戶端瀏覽器首先解釋狀態行,查看請求的狀態碼是否成功,而後解析每個響應頭,客戶端瀏覽器讀取響應數據的HTML,在根據HTML語法在瀏覽器窗口中進行展現

瀏覽器地址欄輸入URL,流程:

  1. 瀏覽器向DNS服務器請求解析該URL中的域名對應的IP地址

  2. 解析出IP地址,根據IP地址和默認端口,和服務器創建TCP鏈接

  3. 瀏覽器發送HTTP請求(包含url後面對應的文件路徑),該請求報文由TCP第三次握手發送給服務器

  4. 服務器對瀏覽器作出相應,將對應的html返回給瀏覽器

  5. 釋放TCP鏈接

  6. 瀏覽器將該html文本進行展現

HTTP 請求方法

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

  • GET:

    • 向指定資源發出顯示請求,使用GET方法只用在讀取數據,
  • POST:

    • 向指定資源提交數據,請求服務器進行處理(如提交表單或者上傳文件),數據被包含在請求文本中
  • HEAD:

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

  • 其他請求:

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

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

    • trace 回顯服務器收到的請求,主要用於測試或診斷

    • options 使服務器傳回該資源全部http請求方法

    • connect HTTP/1.1協議中預留給可以將鏈接改成管道方式的代理服務器

  • 請求注意事項:

    • 方法名稱是區分大小寫的。當某個請求所針對的資源不支持對應的請求方法的時候,服務器應當返回狀態碼405(Method Not Allowed),當服務器不認識或者不支持對應的請求方法的時候,應當返回狀態碼501(Not Implemented)

HTTP 狀態碼

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

  • 2xx成功——請求已成功被服務器接收、理解、並接受

  • 3xx重定向——須要後續操做才能完成這一請求

  • 4xx請求錯誤——請求含有詞法錯誤或者沒法被執行 404:沒有內容 403:沒有權限

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

URL

  • 超文本傳輸協議,統一資源定位獲取五個基本元素,

    https://www.sogou.com/web?query=新聞&_asf=www.sogou.com&_ast=&w=0
    
    # http      傳送協議
    # //        層級URL表示符號,固定格式
    # www.sogou.com   域名,服務器和:端口號
    #/                  區分每一個路徑的的目錄
    #/web           頁面路徑
    #?query=新聞       GET模式查詢的窗口參數(?字符爲起點,每一個參數以&隔開,再以=分開參數名稱和數據)
    #               錨點
    
    請求(瀏覽器發給服務器的數據 request0
        請求方法,路徑,協議版本\r\n  #請求行
        k1:v1\r\n
        k2:v2\r\n                 #請求頭
        \r\n
        請求數據                   #get請求美哦與請求體
    
    響應(服務端返回給瀏覽器的數據 respons)
      格式:
          "協議版本" 狀態碼 狀態描述 \r\n
             k1:v1\r\n
             k2:v2\r\n  
             \r\n
             響應數據(響應體)"html文本"

web框架

  • web框架的本質都是一個socket服務端,而用戶瀏覽器就是一個socket客戶端部,這樣就實現了web框架

web框架的功能:

  1. 使用socket收發消息 (wsgiref wsgi模塊也能夠收發消息,uwsgi線上使用)

  2. 根據不一樣路徑返回不一樣的內容

  3. 返回動態的數據(字符串的替換 模板的渲染 jinja2)

分類:

  • Django 2 3

  • Flask 2

  • tornado 1 2 3

本身寫web框架:

  • 框架示例:

    import socket
    import time
    
    sk = socket.socket()            # 建立一個socket對象
    sk.bind(('127.0.0.1',667))      # 綁定ip和端口
    sk.listen()                     # 監聽
    
    def index(url):
        with open('index.html', 'rb') as f:        #讀取index標籤
            return f.read()
    
    def home(url):
        ret = '歡迎回家! - {}'.format(url)
        return ret.encode('utf-8')
    
    def help_me(url):
        ret = '再等30年,你又是條好漢! - {}'.format(url)
        return ret.encode('utf-8')
    
    def timer(url):
        now = time.time()
        with open('time.html','r',encoding='utf-8') as f:
            ret = f.read()
            ret = ret.replace('@@time@@',str(now))  #將獲取的時間在time中替換展現在頁面上
            return ret.encode('utf-8')
    
    list1 = [
        ('/index', index),
        ('/home', home),
        ('/help_me', help_me),
        ('/time', timer),]
    
    while True:
        conn, addr = sk.accept()  # 等待鏈接
        data = conn.recv(1024)
        url = data.decode('utf-8').split()[1]
    
        func = None
        for i in list1:
            if url == i[0]:
                func = i[1]
                break
    
        if func:
            ret = func(url)
        else:
            ret = '被查辦了!'.encode('utf-8')
    
        conn.send(b'HTTP/1.1 200 OK\r\ncontent-type: text/html; charset=utf-8\r\n\r\n')
        conn.send(ret)
        conn.close()
    
    # index頁面:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1 style="color: forestgreen"> 歡迎光臨! </h1>
    </body>
    </html>
    
    # time頁面:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>當前時間是:@@time@@ </h1>
    </body>
    </html>

Django安裝簡單使用

安裝Django:

  • 命令行方法:

    • 使用django必須是專業版

    • pip3 install django==1.11.23 -i https://pypi.tuna.tsinghua.edu.cn/simple (清華源速度快)

  • 查看是否安裝成功:

    • 查看此目錄是否有django-admin.exe

    • D:\Program Files (x86)\python3.6.8\Scripts

建立項目:

  • 命令行建立:

    • django-admin startproject 項目名稱
  • pycharm建立:

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

      1566393550881

  • 建立後的項目目錄:

    xiangmu/
    ├── idea         # pycharm環境
    ├── manage.py    # 管理文件
    ├─— templates    # html css樣式目錄
    └── xiangmu      # 項目目錄
        ├── __init__.py
        ├── settings.py  # 配置
        ├── urls.py      # 路由 --> URL和函數的對應關係
        └── wsgi.py      # runserver命令就使用wsgiref模塊作簡單的web server
    
    settings.py配置文件:
    ALLOWED_HOSTS = ['*']   #設置能夠訪問的主機,*=全部
    TEMPLATES-->DIRS      #關聯html css文件位置
    
    urls.py URL路徑地址:

啓動項目:

  • 命令行:

    #進入python目錄進行啓動
    
    python manage.py runserver  127.0.0.1:8000
    python manage.py runserver  127.0.0.1:80
    python manage.py runserver  0.0.0.0:80
  • pycharm:

    • pycharm 點綠三角, 不要右鍵運行文件

Django項目建立步驟:

  1. 下載

    命令行:

    ​ pip install django==1.11.23

    ​ pip install django==1.11.23 -i 源的地址

    pycharm

    ​ file——》 settings ——》解釋器 ——》 點+號 ——》 輸入django ——》 選擇版本 ——》下載

  2. 建立項目

    命令行:

    ​ 切換到存項目的目錄下

    ​ django-admin startproject 項目名

    pycharm:

    ​ file ——》 new project ——》 django ——》 輸入項目的路徑 ——》 選擇解釋器 ——》 寫一個APP的名字 ——》 create

  3. 啓動項目

    命令行:

    ​ 切換進去到項目的根目錄 manage.py

    ​ 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

    pycharm:

    ​ 點綠三角 啓動 肯定是django項目

    ​ 可配置ip和端口

  4. 配置settings

    靜態文件

    ​ STATIC_URL = '/static/'

    ​ STATICFILES_DIRS = [

    ​ os.path.join(BASE_DIR,’static‘),

    ​ os.path.join(BASE_DIR,’static1‘),

    ​ ]

    中間件

    ​ csrf 中間件註釋掉 能夠提交POST請求

    INSTALLED_APPS app相關

    數據庫

    模板 DIRS

  5. APP

    建立app

    命令行:

    ​ python manage.py startapp app名稱

    pycharm:

    ​ tools ——> run manage.py task ——> startapp app名稱

    註冊app

    INSTALLED_APPS = [
        # 'app01',
        'app01.apps.App01Config',
    ]

  6. urls.py

    urlpatterns = [
        url(r'^index/', views.index),
        url(r'^home/', views.home),
        url(r'^login/', views.login),
    ]

  7. views.py

    from django.shortcuts import HttpResponse, render, redirect
    
    def index(request,):
        return HttpResponse()

    HttpResponse('字符串') 返回字符串

    render(request,'html文件名') 返回一個html頁面

    redirect(’重定向的地址‘) 重定向

  8. form表單

    1. form標籤的屬性 action ='' 提交的地址 method=’post‘ 請求方式 novalidate 不校驗

    2. input標籤要有name 有些須要value

    3. 有一個類型爲submit的input或者 button

  9. get 和post的分別

    get 獲取一個頁面

    沒有請求體

    ?k1=v1&k2=v2

    django 中獲取 request.GET request.GET['k1'] request.GET.get('k1','xxxx')

    post 提交數據 數據隱藏

    django 中獲取 request.POST request.POST['k1'] request.POST .get('k1','xxxx')

orm-增刪改查:

  • __str__和__repr__區別

    有時候咱們想讓屏幕打印的結果不是對象的內存地址,而是它的值或者其餘能夠自定義的東西,以便更直觀地顯示對象內容,能夠經過在該對象的類中建立或修改__str__()或__repr__()方法來實現(顯示對應方法的返回值)
    
    # 兩種觸發方式:
        使用print()時
        使用%s和f'{}'拼接對象時
        使用str(x)轉換對象x時
    
    在上述三種場景中,會優先調用對象的__str__()方法;若沒有,就調用__repr__()方法;若再沒有,則顯示其內存地址。
    
    # 特別地,對於下面兩種場景:
        用%r進行字符串拼接時
        用repr(x)轉換對象x時
      則會調用這個對象的__repr__()方法;若沒有,則再也不看其是否有__str__()方法,而是顯示其內存地址

  • 建立表數據

    from django.db import models
    
    class Publisher(models.Model):                # Publisher:表名,繼承models.Model類
        pid = models.AutoField(primary_key=True)  # 自增、主鍵
        name = models.CharField(max_length=32,unique=True)
    
        def __str__(self):
            return "{}{}".format(self.pid,self.name)  # 返回給調用者內容

  • 查詢展現數據:

    #查詢全部數據
    all_publisher = models.Publisher.objects.all()  
    
    #將數據返回到前端
    return render(request,'publisher_list.html',{'all_publisher':all_publisher})
    
    #展現數據
    from django.shortcuts import render,HttpResponse,redirect
    from app import models
    
    
    #從數據庫中展現數據
    #從數據庫中查詢出全部的出版社
    #從數據庫中查詢的數據展現到前端頁面
    def publisher_list(request):
        all_publisher = models.Publisher.objects.all().order_by('pid') 
        return render(request,'publisher_list.html',{'all_publisher':all_publisher})

  • 模板的語法:

    {{  all_publishers }}    變量
    
    {% for  i in  all_publishers  %}  #for循環
    
      {{ forloop.counter }}         #循環打印的內容
      {{  i }}
    
     {% endfor %}                       #閉合

  • 新增數據:

    # 方式一:經過create將數據插入到數據庫中(推薦)
    ret = models.Publisher.objects.create(name=pub_name)
    return redirect("/publisher_list")  
    
    #方式二:先建立對象在save進行保存
    obj = models.Publisher(name=pub_name)
    obj.save()
    
    
    #新增出版社 
    def publisher_add(request):                           
        pub_name,error='',''
        if request.method == "POST":                    #判斷前端是POST類型仍是GET類型
            pub_name = request.POST.get('pub_name')     #經過POST獲取前端的出版社名稱
    
            if not pub_name:
                error = "輸入不能爲空"
            elif models.Publisher.objects.filter(name=pub_name):
                error = "數據已經存在"
            else:                                     #經過create將數據插入到數據庫中(推薦)
                models.Publisher.objects.create(name=pub_name)  
                return redirect("/publisher_list")
    
        return render(request, 'publisher_add.html', {'pub_name': pub_name, 'error': error})

  • 刪除數據

    pk = request.GET.get('pk')
    query = models.Publisher.objects.filter(pk=pk)  # 對象列表
    query.delete()     # 經過queryset 刪除
    query[0].delete()  # 經過單獨的對象 刪除
    
    
    # 刪除數據
    def publisher_del(request):       
        pk_id = request.GET.get('pk')        # 獲取前端URL數據
        query = models.Publisher.objects.filter(pk=pk_id)
        if not query:
            return HttpResponse("要刪除的數據不存在")
        query.delete()                     # 參數有多個刪除多個,query[0].delete()#只刪除一個
        return redirect("/publisher_list")

  • 編輯數據

    obj = models.Publisher.objects.filter(pk=pk).first()  # 對象列表中第一個對象
    obj.name = pub_name  # 內存中修改
    obj.save()             # 提交
    
    #編輯數據
    def publisher_edit(request):   
        error=""
        pk_id = request.GET.get("pk")   #url地址攜帶的參數,first()查出多個只取一個,沒有不報錯
        obj = models.Publisher.objects.filter(pk=pk_id).first()
    
        if not obj:
            return HttpResponse("編輯的對象不存在")
    
        if request.method == "POST": # 獲取新提交的數據,編輯原始的對象
            pub_name = request.POST.get('pub_name')
    
            if not pub_name:
                error = "輸入不能爲空"
            elif models.Publisher.objects.filter(name=pub_name):
                error = "數據已經存在"
            else:
                obj.name = pub_name
                obj.save()
                return redirect("/publisher_list")
        return render(request,'publisher_edit.html',{'obj':obj,'error':error})

ORM一對多關係:

外鍵的設計

# ForeignKey 添加的外鍵('Publisher' 添加字符串經過反射進行查找)
    on_delete=models.set(1)   惟一
    default=11,on_delete=models.DEFERRED   默認值
    null=True on_delete=models.SET_NULL     設置字段可有爲空
    on_delete=models.DO_NOTHING             什麼操做都不作

# on_delete  2.0 必填 ,關聯刪除後的選項
class Book(models.Model):
    id = models.AutoField(primary_key=True)  # 自增、主鍵
    title = models.CharField(max_length=32)
    pid = models.ForeignKey('Publisher', on_delete=models.CASCADE) #默認關聯主鍵

增刪改查

  • 查詢:

    all_books = models.Book.objects.all()
    print(all_books)
    
    for book in all_books:
        print(book)
        print(book.pk)
        print(book.title)
        print(book.pub,type(book.pub))      # 一對多關聯的是對象 
        print(book.pub_id,type(book.pub_id))  # 所關聯的對象的pk
        print('*' * 32)

  • 新增

    #pub=models.Publisher.objects.get(pk=pub_id)  只能等於一個對象
    models.Book.objects.create(title=title,pub=models.Publisher.objects.get(pk=pub_id))
    
    #第二種方法,pub外鍵必須等於一個對象,可是都要轉換成id,因此第二種方法直接添加ID也能夠
    models.Book.objects.create(title=title, pub_id=pub_id)

  • 刪除

    pk = request.GET.get('pk')
    models.Book.objects.filter(pk=pk).delete()

  • 編輯

    book_obj.title = title
    book_obj.pub_id = pub_id
    
    #第一種方法
    book_obj.pub = models.Publisher.objects.get(pk=pub_id)
    book_obj.save()
    
    #第二種方法
    book_obj.pub_id = new_pub_id     #將數據保存
    book_obj.save()

ORM 多對多關係:

多對多關係建立

  • 第一種方法:django經過ManyToManyField自動建立第三張表

    # 在上下兩個表中添加均可以,只是順序不同
    class Book(models.Model):
       title = models.CharField(max_length=32)
       pub = models.ForeignKey('Publisher', on_delete=models.CASCADE)
       # authors = models.ManyToManyField('Author')  # 描述多對多的關係   不生成字段  生成關係表
    
        def __repr__(self):
            return self.title
    
        __str__ = __repr__
    
    class Author(models.Model):
        id = models.AutoField(primary_key=True)  # 自增、主鍵
        name = models.CharField(max_length=32)
        books = models.ManyToManyField('Book')  # 描述多對多的關係   不生成字段  生成關係表

  • 第二種方法:本身手動建立

    class Book(models.Model):
        title = models.CharField(max_length=32)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
    
    
    class Book_Author(models.Model):
        book = models.ForeignKey(Book, on_delete=models.CASCADE)
        author = models.ForeignKey(Author, on_delete=models.CASCADE)
        date = models.DateField()     #本身建立表能夠添加多個字段(時間字段)

  • 第三種方法:本身建立 + ManyToManyField

    # 第三張表包含了第一張和第二張表的使用方法
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
      #第三種方法:to book表字段,through=指定多對多關係
        books = models.ManyToManyField(Book, through='Book_Author')  
    
    
    class Book_Author(models.Model):   #建立關係表
        book = models.ForeignKey(Book, on_delete=models.CASCADE)
        author = models.ForeignKey(Author, on_delete=models.CASCADE)
        date = models.DateField()

多對多-增刪改查

  • 查詢:

    def author_list(request):
        all_author = models.Author.objects.all().order_by("id")
    
        for author in all_author:
            print(author)
            print(author.name)
            print(author.pk)
            print(author.books)         #多對多拿到books是關係對照表
            print(author.books.all())   #經過all拿到關聯的全部對象
            print("*"*32)
        return render(request,'author_list.html',{'all_author':all_author})
    
    # 從book表中查詢author做者數據,下面是獲取到author對象
      book.author_set.all  
    
    
    # 前端展現示例:
      <tbody>
             {% for author in all_author %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ author.pk }}</td>
                        <td>{{ author.name }}</td>
                        <td>
                            {% for book in author.books.all %}
                                    《{{ book.title }}》
                            {% endfor %}
                        </td>
                        <td>
                            <a href="">刪除</a>
                            <a href="">編輯</a>
                        </td>
                     </tr>
            {% endfor %}
     </tbody>

  • 新增:

    books = request.POST.getlist('books')               # 獲取多個元素
    author_obj = models.Author.objects.create(name=name)  # 新建做者
    author_obj.books.set(books)                         #【id,id】,給做者和書籍綁定關係
    
    
    #新增示例:
    def author_add(request):
        if request.method == "POST":
            name = request.POST.get('name')
            books = request.POST.getlist('books')  #列表方式獲取書籍ID ['1']
    
            author_obj = models.Author.objects.create(name=name)   #做者名寫入數據庫
            author_obj.books.set(books)                              #寫入關聯方式
            return redirect("/author_list/")
    
        all_books = models.Book.objects.all()
        return render(request,'author_add.html',{'all_books':all_books})

  • 刪除:

    def author_del(request):
        pk_id = request.GET.get("pk")
        models.Author.objects.filter(pk=pk_id).delete()
    
        return redirect('/author_list/')

  • 編輯:

    def author_edit(request):
        pk_id = request.GET.get("pk")
        obj = models.Author.objects.filter(pk=pk_id).first()
    
        if request.method == "POST":
            name = request.POST.get('name')
            books = request.POST.getlist('books')  #列表方式獲取書籍
    
            obj.name = name                #修改做者名稱
            obj.save()
            obj.books.set(books)           #添加做者關聯的書籍地址,每次都是刪除後在添加
            return redirect('/author_list//')
    
        all_books = models.Book.objects.all()
        return render(request,'author_edit.html',{'obj':obj,'all_books':all_books})
    
    # 前端示例
        <form action="" method="post">
            <p>
                做者:<input type="text" name="name" value="{{ obj.name }}">
            </p>
    
            <p>
                著做:<select name="books" id="" multiple>
                    {% for book in all_books %}
                        {% if book in obj.books.all %}
                                <option selected value="{{ book.pk }}">{{ book.title }}</option>
                            {% else %}
                                <option value="{{ book.pk }}">{{ book.title }}</option>
                        {% endif %}
    
                    {% endfor %}
    
                </select>
            </p>
            <button>提交</button>
        </form>

模板使用:

MVC 和 MTV

  • MVC:

  • mvc是軟件中一種軟件架構模式,把軟件系統分爲三個基本部分,具備耦合性低,重用性高,生命週期成本低

    • M: model 模型 和數據庫交互
    • V:view 視圖 展現頁面 HTML
    • C: controller 控制器 調度 業務邏輯
  • MTV:

    • M : model 模型 操做數據庫 orm、

    • T : template 模板 HTML

    • V: view 視圖 業務邏輯

經常使用語法:

  • {{ 變量 }} :兩個大括號 表示變量,在模板渲染的時候替換成值

  • {{% 邏輯%}} : 括號中帶有兩個百分號表示邏輯相關操做

變量

  • {{ 變量名. }}

    • ​ .索引 .key .屬性 .方法
    • 列表.索引 字典.key 類.屬性 類.方法
  • 示例:

    # 模板中的變量是經過views render後端返回到前端,前端經過{{}}顯示到頁面
    # 注意事項:在字典中建立跟字典方法相同key 會優先調用字典中的key > 對象的屬性或方法 > 列表的索引  
    
    {{ name_list.1 }}  拿到列表第一個索引
    {{ dic.name }}     經過字典的key取值
    {{ dic.keys }}     字典的數據類型,keys
    {{ dic.values }}   字典的數據類型,values
    
    {{ p1 }}         類中方法,在類中定義str返回值,返回全部值
    {{ p1.name }}    返回name屬性
    {{ p1.talk }}    調用類中方法,不用加括號
    
    
    #views
    def index(request):
        class Person():
            def __init__(self,name,age):
                self.name = name
                self.age  = age
    
            def talk(self):
                return "我太難了"
    
            def __str__(self):
                return f"Person obj:{self.name}{self.age}"
    
        booll = True
        num = 666
        string = "小窩窩"
        name_list = ["海洋","俊麗","小寶寶","大寶寶"]
        dic = {
            "name":"小明",
            "age":"18",
            "sex":"18",
            'hobby':["檯球","籃球","足球",'羽毛球']}
    
        p1 = Person("胡海洋",18)
    
        context = {
            'booll':booll,
            'num':num,
            'string':string,
            'name_list':name_list,
            'dic':dic,
            'p1':p1}
        return render(request,'index.html',context)
    
    # templates
    <body>
        {{ booll }}<br>
        {{ num }}<br>
    
        {{ string }}<br>
    
        {{ name_list.1 }}<br>
    
        {{ dic.values }}<br>
    
        {{ p1}}
        {{ p1.name }}
        {{ p1.talk }}
    </body>

過濾器-Filters(管道)

  • 修改變量的顯示結果

  • 語法

    • {{ value|filter_name }} {{ value|filter_name:參數 }}

  • default: 提供默認值

    # 傳過來的變量不存在或者爲空 使用默認值,:後面不能夠有空格!!!
    {{ qq|default:'默認值本身設置' }}
    
    # 後端變量若是無效能夠增長提示
    注:TEMPLATES的OPTIONS能夠增長一個選項:string_if_invalid:'找不到',能夠替代default的的做用。

  • 列表切片

    {{ name_list|slice:'::-1' }}   從後往前切片
    {{ name_list|slice:'0:2' }}    切兩個值

  • filesizeformat 文件大小格式化

    • 將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)

      {{ filesize|filesizeformat }}
      
      後端:'filesize':1*1024*1024

  • add

    數字的加法   字符串的拼接  列表的合併
    
    {{ num|add:2 }}            # 給數字進行加2,若是num爲字符串類型也會進行相加
    {{ string|add:"haha"}}       # 經過add給string字符串進行拼接
    {{ name_list|add:name_list}} # 列表拼接
    
    {{ num|add:-2 }}           減法
    {% widthratio num 1 4%}  乘法
    {% widthratio num 2 1%}  除法 # 1放在中間時乘法,放在後面是除法

  • 其餘內置過濾器方法

    • 字符串

      • 變小:{{ string|lower}}
      • 變大:{{ string|upper}}
      • 計數:{{ string|length}}
    • 列表

      • 取第一個元素: {{ name_list|first}}

      • 取最後一個元素 : {{ name_list|last}}

      • 字符串拼接列表: {{ name_list|join:'**'}}

      • 按字符串長度取值: {{ string|truncatechars:'10'}} ,truncatewords按照單詞區分

  • 日期格式化:

    {{ now|date:'Y-m-d H:i:s' }}  年月日時分秒
    {{ now|date}}               設置settings後使用方法
    {{ now|time}}
    # 後端格式
      'now':datetime.datetime.now()
    
    # settings 配置
    USE_L10N = False
    DATETIME_FORMAT = 'Y-m-d H:i:s'
    DATE_FORMAT = 'Y-m-d'
    TIME_FORMAT = 'H:i:s'

  • safe 告訴django不須要「」轉義:

    {{ js|safe }}
    {{ a|safe }}
    
    # 後端js,字符串在前端仍是普通字符串,想要展現效果,添加safe不須要轉義
    'js':'''
            <script>
                for (var i = 0; i < 5; i++) {
                    alert('11111')
                }
            </script>
       '''
    'a':'<a href="http://www.baidu.com">跳轉</a>'

  • PY文件中不轉義方法

    # 第二種方法mark_safe 在後端進行處理,前端直接調用:
    
    {{ a }}   # 調用
    
    from django.utils.safestring import  mark_safe
    'a':mark_safe('<a href="http://www.baidu.com">跳轉</a>')

自定義過濾器

  1. 在app下建立一個名爲templatetags的python包(文件夾)

  2. 在包內建立py文件 —— 》 自定義 my_yags.py

  3. 在py文件中寫入:

    from django import template
    register = template.Library()  # register不能變
  4. 定義函數 + 加裝飾

    @register.filter
    # new_upper(|後面的方法)  value(本來的變量) arg最多有一個(冒號就後面的參數,可默認)
    
    def new_upper(value, arg=None):  # arg 最多有一個
        print(arg)
        return value.upper()         # 不返回 前端結果爲None
  5. 在模板中使用:

    {% load my_yags %}          # 加載寫函數定義的文件
    
    {{ string|new_upper:dic }}  # string變量,new_upper函數方法,dic後端數據,能夠返回到函數arg中

for 循環

  • forloop

    # for 循環格式
    {% for name in name_list %}
        <li> {{ forloop.counter0 }} - {{ name }}</li>
    {% endfor %}
    
    {{ forloop.counter0 }}     字典中都已經定義好了一下參數
    {{ forloop.counter }}      當前循環的從1開始的計數
    {{ forloop.counter0 }}     當前循環的從0開始的計數
    {{ forloop.revcounter }}   當前循環的倒敘計數(到1結束)
    {{ forloop.revcounter0 }}  當前循環的倒敘計數(到0結束)
    {{ forloop.first}}         當前循環是不是第一次循環  布爾值
    {{ forloop.last}}        當前循環是不是最後一次循環  布爾值
    {{ forloop.parentloop }}   當前循環父級循環的forloop(多層循環中才能夠查看到)
  • empty

    {% for name in name_list %}
        {{ name }}
    
    {% empty %}
        空的數據,循環過程沒有數據返回此提示
    {% endfor %}

if 判斷

  • if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷。

    # 判斷列表中爲偶數的變顏色,if裏面可使用過濾器
    <table border="1">
        <tbody>
            {% for name in name_list2 %}
                <tr>
                    {% for new in name %}
                        {% if forloop.counter|divisibleby:2 and forloop.parentloop.counter|divisibleby:2%}
                                <td style="background-color: yellow">{{ new }}</td>
                            {% else %}
                                <td>{{ new }}</td>
                        {% endif %}
                    {% endfor %}
                </tr>
            {% endfor %}
        </tbody>
    </table>
    
    
    # 多層判斷
        {% if p1.age < 18 %}
            寶寶
        {% elif p1.age == 18 %}
            剛成年
        {% else %}
            上班
        {% endif %}
    
    # 不支持算數運算 
      {% if 1 + 2 == 3 %}
        {% if 1|add:2 == 3 %}  能夠這樣寫
    
    # 不支持連續判斷
      {% if 10 >5 > 1 %}

with和csrf_token

  • with示例:

    # 取別名兩種方式
    {% with alex=person_list.1.name age=person_list.1.age   %}
        {{ alex }} {{ age }}
        {{ alex }}
    {% endwith %}
    
    {% with person_list.1.name as junli %}
        {{ junli }}
    {% endwith %}

  • {% csrf_token %}

    # {% csrf_token %}標籤放在form標籤中,不安全報錯403
    # form表單中有一個隱藏的input標籤(name  ='csrfmiddlewaretoken'),後端經過這個值進行驗證
    
    <form action="" method="post">
        {% csrf_token %}   
    </form>

母板和繼承

  • 母板就是將公共部分提取出來,不重複的定義block,以後再進行集成填充block塊,減小重複代碼,提升效率

  • 母板

    • html頁面 提取多個頁面的公共部分

    • 定義多個block塊,須要讓子頁面覆蓋填寫

      # 找到重複的頁面定義bolck塊
      
      # 第一種block塊,設置母版
      <div class="col-sm-3 col-md-2 sidebar">
      <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
              {% block content %}
              <h1>母版</h1>
              {% endblock %}
       </div>
      
      # 第二種block能夠設置爲參數
          <ul class="nav nav-sidebar">
              <li class="{% block pub_active%}{% endblock %}">
              <li class="{% block book_active%}{% endblock %}">
              <li class="{% block author_active%}{% endblock %}">
          </ul>
      
      
      # 每一個頁面的css樣式,在繼承中填寫link
          {% block  css%}
      
          {% endblock %}

  • 繼承母版:

    • {% extends ‘母板文件名’ %}

    • 重寫block塊 ,寫在block內部

      {% extends 'base.html' %}     # 引用母版文件
      
      {% block content %}
                  <h3 class="sub-header"> 出版社列表 </h3>   #填寫block塊,將代碼覆蓋添加到塊中
              <div class="table-responsive">
      {% endblock %}
      
      
      {% block book_active %}      # 重寫block會覆蓋block內的內容
          active  
      {% endblock %}
      
      
      {% block css %}              # 重寫每一個頁面文件的樣式,這樣避免重複,公共樣式寫在母版中
          <link rel="stylesheet" href="">
      {% endblock %}

  • 注意:

    • 注意事項

      • {% extends 'base.html' %} 帶上引號 不帶的話會當作變量

      • {% extends 'base.html' %} 上面不要寫其餘內容,不然會顯示出來

      • 要顯示的內容寫在block塊中

      • 母板能夠定義多個block 定義 css js,每一個子頁面繼承本身的css和js樣式

組件

  • 組件就是將一段經常使用HTML代碼段存放單獨的html中,想調用直接引用

  • include組件示例:

    #組件其實就是將代碼進行拆分
    #新建一部分代碼如導航欄,存放在 nav.html中
    
    #拆分的組件可使用include在母版中,也可使用在單獨的html中:
    {%  include  ‘nav.hmtl ’ %}

靜態文件相關

  • 引入靜態文件:

    # 從配置文件中自動找到static別名
    # 第一種方式
    {% load static %} 
    <link rel="stylesheet" href="{% static 'css/dashboard.css' %}">
    
    # 第二種方式
    <link rel="stylesheet" href="{% get_static_prefix %}css/dashboard.css">

定義 filter simple_tag inclusion_tag

  1. 在app下建立templatetags的python包文件

  2. 在包內建立py文件 my_tags.py

  3. 在py文件中寫代碼:

    from django import  template
    register = template.Library()
  4. 定義函數 + 加裝飾器

  • filter 過濾器方法

    @register.filter   
    def add_arg(value,arg):          # 只能接受兩個
       return  "{}_{}".format(value,arg) 
    
    {% load my_yags %}                 # 加載寫函數定義的文件,不能夠嵌套,能夠在for循環if裏使用
    {{ string|new_upper:"haha" }}

  • simple_tag 方法:

    # 能夠接受多個參數
    @register.simple_tag            
    def join_str(*args, **kwargs):
        return '_'.join(args) + "*".join(kwargs.values())
    
    # 調用方法
    {% load my_tags %}
    {% join_str "v1" "v2" k3="v3" k4="v4"%}

  • inclusion_tag 方法

    # my_tags中填寫 inclusion_tag函數
    @register.inclusion_tag('page.html')  # 必須制定頁面,並且是動態,要不和組件同樣
    def page(num):
       return {'num':range(1,num+1)}        # 返回必須是字典交給模板,接受HTML返回的參數,返回給page
    
    
    # 前端頁面調用 page函數
        {% load my_tags %}
        {% page  5%}
    
    
    # page.heml 頁面添加一些分頁功能,接受page發送剛過來的參數num
        </li>
         {% for i in num  %}
             <li><a href="#">{{ i }}</a></li>
                 {% endfor %}
         <li>

視圖

  • 視圖系統,是一個簡單的python函數,接受web傳過來的請求,並向web進行響應,響應能夠是html,重定向,錯誤提示啊,不管你的視圖包含什麼邏輯,都須要返回響應

  • FBV: function based view

  • CBV: class based view

    • cbv示例:

      from django.views import View
      
      class AddPublisher(View):
          def get(self,request):  #處理get請求
              return xx
      
          def post(self,request): #處理post請求
              return xx
      
      # urls調用
      url(r'^publisher_add/',views.AddPublisher.as_view() ),

CBV的流程

  • 看這個cbv流程主要是要知道request和get是怎麼執行的

  • 項目啓動時,運行urls.py

    url(r'^publisher_add/',views.AddPublisher.as_view() )  # 執行as_view() 函數
    AddPublisher.as_view() 執行  ——>   view函數    # 將此函數AddPublisher傳給 as_view()
    
    # view函數
        def as_view(cls, **initkwargs):        # cls = AddPublisher   
            def view(request, *args, **kwargs):  # reqyest 前端的請求  
                self = cls(**initkwargs)       # AddPublisher實例化對象self
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                    self.request = request       # 類中使用的request就是self.request
                    self.args = args
                    self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)  # 調用dispatch方法
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            update_wrapper(view, cls, updated=())
            update_wrapper(view, cls.dispatch, assigned=())
            return view
  1. 請求到來時,實行view函數:

    1. 實例化AddPublisher ——> self

    2. self.request = request

    3. 執行View中self.dispatch(request, *args, **kwargs)

      def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names: # 判斷請求是否被准許,方法有八種
            handler = getattr(self, request.method.lower(),                                                     self.http_method_not_allowed)  # 反射,判斷請求是否錯誤
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)             # 執行 handler=get加括號
      
      # 判斷請求方式是否被容許
          容許
            經過反射獲取請求方式對應的方法     ——> handler  
          不容許
            self.http_method_not_allowed  ——> handler   # 返回的是錯誤代碼信息
      
      執行handler 獲取到響應

視圖加裝飾器

  • 裝飾器函數:

    # 視圖添加裝飾器,先建立好裝飾器
    def timer(func):
        def inner(*args,**kwargs):
            start = time.time()
            ret = func(*args,*kwargs)
    
            print(f"{time.time()-start}")
            return ret
        return inner

  • FBV 函數添加裝飾器直接加:

    @timer
    def publisher_edit(request):   #編輯數據
        pass

  • CBV 類中方法添加裝飾器:

    # 第一種在方法中添加:
        from django.utils.decorators import method_decorator
    
        class AddPublisher(View):
            @method_decorator(timer)
            def get(self, request):  # 處理get請求
                print('get')
                return  render(request, 'publisher_add.html')
    
    
    # 第二種在dispatch上添加,這樣全部請求都帶有裝飾器功能:
        @method_decorator(timer)
        def dispatch(self, request, *args, **kwargs):
              print("dispatch 前")
                ret = super().dispatch(request,*args,**kwargs)
                print("dispatch 後")
                return ret
    
    
    # 第三種加在類上面:
        @method_decorator(timer,name='post')
        @method_decorator(timer,name='get')
      @method_decorator(timer,name='dispatch')
        class AddPublisher(View):
          pass

request:

  • 獲取請求參數:

    request.method      # 請求方式  GET POST 
    request.GET         # url上攜帶的參數  {}   get()
    request.POST        # post請求提交的參數  {}   get()
    
    request.META          # http頭部的信息,具體信息取決於客戶端和服務器,獲取頁面request headers
    request.body          # 請求體的數據  post也是在body裏面取值的
    
    request.path_info     # 獲取路徑信息  不包含IP和端口 也不包含查詢參數
    request.FILES     # 獲取上傳的文件 
    request.scheme        # 獲取前端是http或者是https字符串
    
    request.COOKIES       # cookie 記錄狀態 鍵值對存儲在瀏覽器
    request.session   # session 記錄狀態,鍵存儲在瀏覽器,值存儲在數據庫中,更安全些
    
    request.get_full_path()   # 完整的路徑信息 包含查詢參數 不包含IP和端口 
    request.is_ajax()           # 判斷是不是ajax請求

  • 上傳文件注意事項:

    # form表單的屬性  enctype="multipart/form-data"
    # input   type = 'file'
    # request.FILES.get('f1')      
    
    class File_upload(View):
        def get(self,request):
            return render(request,'file_upload.html')
    
        def post(self,request):
            file_obj = request.FILES.get('f1')
            with open(file_obj.name,'wb') as f:
                for i in file_obj.chunks():
                    f.write(i)
            return HttpRespose("ok")
    
    # 前端頁面:
    <form action="" method="post" enctype="multipart/form-data">
        <p>
               上傳文件:<input type="file" name="f1" multiple>
        </p>
        <button>上傳</button>
    </form>

response

  • HttpResponse('字符串') # 返回字符串

  • render(request,'模板的文件名',{}) # 返回一個完整的頁面

    def render(request, template_name, context=None, content_type=None, status=None, using=None):
      # content loader.render_to_string 這裏已經將模板頁面進行渲染完成
        content = loader.render_to_string(template_name, context, request, using=using)
      # 將content內容封裝成httpresponse對象
        return HttpResponse(content, content_type, status)

  • redirect('要跳轉的地址') # 重定向 響應頭 Location: url

  • 301: url後面不添加/ 302:添加/會直接永久重定向

    def redirect(to, *args, **kwargs):
        if kwargs.pop('permanent', False):
            redirect_class = HttpResponsePermanentRedirect  # 301 暫時重定向
        else:
            redirect_class = HttpResponseRedirect           # 302 永久重定向
    
        return redirect_class(resolve_url(to, *args, **kwargs))

  • 先後端分離-JSON:

    # 第一種json傳參方法:
    import json
    def get_data(request):
        data = {'status':0,'data':{'k1':'v1'}}
      return HttpResponse(json.dumps(data),content_type='application/json')
    
    # 第二種簡單方法(經常使用,前端自動進行反序列化):
    def get_data(request):
        data = {'status':0,'data':{'k1':'v1'}}
      return JsonResponse(data)
    
    # 不是字典,列表的話須要添加safe=False
    from django.http.response import JsonResponse
    def get_data(request):
        l1 = ["1",'2','3']
      return JsonResponse(l1,safe=False)

路由

  • 路由的本質就是,url與調用的視圖函數之間的映射表,也就是說你訪問我哪一個url路由執行相對應的函數

  • 路由匹配的只是路徑,獲取的參數永遠只是字符串

  • urls的基本配置

    from django.conf.urls import url
    from django.contrib import admin
    from app import views
    urlpatterns = [
         url(正則表達式, views視圖,參數,別名),
    ]

正則表達式

  • 正則規則

    • 以什麼開頭^ 結尾$ [0-9] [a-zA-Z]{4}

    • . 數字:\d 數字和字母:\w 0個或者多個:? 至少一個:+ 0和或者無數個:*

  • 從上到下的進行匹配 匹配到一個再也不往下進行匹配,開頭不加 / ,遊覽器後面/自動添加

    urlpatterns = [
        url(r'^admin/', admin.site.urls),              # r轉義,^以什麼開頭,前面不加/
        url(r'^blog/$', views.bolg),                   # 若是上下第一層目錄相同,添加$表示結尾
        url(r'^blog/[0-9]{4}/[0-9]{2}/$', views.bolgs),  # 簡單的動態路由能夠匹配多個
    ]

分組和命名分組

  • 從URL上獲取到的參數的類型都是字符串,獲取的參數按照位置參數傳遞給視圖函數

    # urls
        urlpatterns = [
            url(r'^blog/([0-9]{4})/([0-9]{2})/$', views.bolgs),]
    
    # views
        def bolgs(request,year,month):   #year和month按照順序接受分組前端返回信息
            print(year)
            print(month)
            return HttpResponse("首頁")

  • 命名分組:獲取的參數按照關鍵字參數傳遞給視圖函數,視圖中實參能夠指定默認值

    urlpatterns = [
        url(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.bolgs),
    ]
    
    
    def bolgs(request,year,month):   #year和month按照順序接受分組前端返回信息,先後端命名相同
        print(year)
        print(month)
        return HttpResponse("首頁")

路由分發include:

  • 分發示例:

    # luyou
    from django.conf.urls import url,include
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # url(r'^',include('ap.urls')),        # 匹配時爲空,跟以前相同都是一級目錄
        url(r'^app/',include('app.urls')),         # 匹配app中的目錄
        url(r'^app01/',include('app01.urls'))    # 能夠匹配多個app
    ]
    
    # app
    from django.conf.urls import url
    from app import views
    
    urlpatterns = [
        url(r'^blog/$', views.bolg),     #$表示結尾
        url(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.bolgs),
    ]

命名URL和URL反向解析

  • 命令url和反向解析,解決了路徑寫死問題,讓路徑修改更加靈活

  • 命名url

    urlpatterns = [
        url(r'^admin/', admin.site.urls,),
        url(r'^publisher_list/',views.publisher_list.as_view(),name='publisher'),]

  • 反向解析:

    • 模板

      # 模板解釋方法,經過命令url中的設置的name,獲取到真實路徑
      
      <a href="{% url 'publisher' %}">出版社列表 </a>
    • py文件

      # py文件中使用,也是經過name獲取到路徑
      from  django.urls  import reverse
      
      def AddPublisher(request):
          return redirect(reverse('publisher'))  #redirect('publisher') 相同

  • 分組命名URL

    • 分組命令url

      # url命名動態路由
      urlpatterns = [
          url(r'^blogs/([0-9]{4})/([0-9]{2})/$', views.bolgs,name='blogs'),
          url(r'^home/$', views.home), ]

    • 反向解析

      • 模板

        # 模板中反向解析
        <a href="{% url 'blogs' '2019' '12' %}">xxx</a>
        
        # views
        def home(request):
            return render(request,'home.html')
      • py文件

        def home(request):
            return redirect('blogs','2020','10')

  • 命名分組URL(瞭解)

    • 分組命名

      url(r'^blogs/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.blogs,name='blogs'),
    • 反向解析

      • 模板

        <a href="{% url 'blogs' year='2019' month='13' %}">xxx</a>
      • py文件

        from  django.urls  import reverse
        reverse('blogs',args=('2019','09'))   ——> /app01/blogs/2019/09/
        
        reverse('blogs', kwargs={'year': '2019', 'month': '12'})     ——> /app01/blogs/2019/12/

namesapce 名稱空間

  • 名稱空間示例,解決命名分組相同問題

    # app,app01
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        url(r'^app/',include('app.urls',namespace='app')),
        url(r'^app01/',include('app01.urls',namespace='app01')),
    ]
    
    # app
    urlpatterns = [
        url(r'^home/$', views.home,name='home'),]
    
    def home(request):
        return render(request,'home.html')
    
    # app01 
    urlpatterns = [
        url(r'^home/$', views.home,name='home'),]
    
    def home(request):
        return render(request,'home1.html')
  • 反向解析

    # app:blogs 起了相同的name時,根據名稱空間來區分
    
    <a href="{% url 'app:blogs' year='2019' month='13' %}">xxx</a>

示例:

  • html模板

    <a href="{% url 'delete' 'author' author.pk %}">刪除</a>
  • urls

    url(r'(\w+)_del/(\d+)/$',views.delete,name='delete')
  • views

    def delete(request, table, pk):
        print(table, pk)
        # 查詢到對應的數據進行刪除
        model_cls = getattr(models, table.capitalize(),)
        model_cls.objects.filter(pk=pk).delete()
        # 重定向
        return redirect(reverse(table))

ORM

  • orm對象關係映射,對象和關係型數據庫的對應關係,將程序中的對象保存到數據庫中

    • 根據對象類型生成表結構
    • 將對象操做轉爲sql語句,在將sql語句查詢到的結果轉換爲對象
    • 做用:減小了開發的工做量,不用面對數據庫操做

  • 注意不一樣的django和不一樣版本的mysql存在兼容性

    • 類 表
    • 屬性 字段
    • 對象 數據行

orm關係映射

  • str

    # str返回的只是顯示出來信息
    def __str__(self):
    return f"{self.pid}{self.name}{self.age}{self.bith}"

admin

  • 建立一個超級用戶

  • python36 manage.py createsuperuser admin

  • 輸入用戶名和密碼

    • 註冊

    • 在app下的admin.py中寫

      from django.contrib import admin
      from app01 import models
      
      admin.site.register(models.Person)   #註冊 Person(model中的表名)
  • 登錄網頁http://127.0.0.1:8000/admin/(找到對應的表作增刪改查)

  • 修改帳號密碼:python manage.py changepassword admin

腳本運行

import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lainxi.settings")
django.setup()
from app01 import models  #放在最後面引入

ORM 經常使用字段

  • 經常使用字段

    • AutoField 主鍵

      #自增的整形字段,必填參數primary_key=True,則成爲數據庫的主鍵。無該字段時,django自動建立。
      #一個model不能有兩個AutoField字段。
      
      pid  = models.AutoField(primary_key=True)
    • CharField 字符串

      #字符類型,必須提供max_length參數。max_length表示字符的長度。
      name = models.CharField(max_length=32)
    • IntegerField 整型

      #-21億到正21億
      age = models.IntegerField()
    • DecimalField 十進制小數

      max_digits=5      #總長度五位
      decimal_places=2  #小數位長度  999.99
      
      price = models.DecimalField(max_digits=5,decimal_places=2,default=0)

    • DateTimeField 日期時間

      auto_now和auto_now_add和default參數是互斥的,不能同時設置
      
      # auto_now=True 每次修改時間,都會變化
      bith = models.DateTimeField(auto_now=True) 
      
      # auto_now_add=True  #新增數據,自動添加時間
      bith = models.DateTimeField(auto_now_add=True)

  • 其餘字段

    BooleanField(Field)        #布爾值
    NullBooleanField(Field)    #能夠爲空的布爾值
    
    BigIntegerField(IntegerField)     #存入的數字更多
    BigAutoField(AutoField)           #自增存入的數字更多
    SmallIntegerField(IntegerField)   #小整數 -32768 ~32767
    FloatField(Field)                   #浮點數
    
    TextField              #存儲大字符串多內容
    EmailField(CharField)    #判斷字符串是不是email格式
    IPAddressField(Field)    #判斷字符是不是IPV4格式
    URLField(CharField)      #判斷是不是正常的url地址
    UUIDField(Field)         #uuid格式校驗
    FilePathField(Field)     #存儲文件路徑
    FileField(Field)         #存儲文件
    ImageField(FileField)    #存儲圖片
    
    DateField()        #日期格式
    TimeField()            #時間格式

  • 自定義char字段

    class MyCharField(models.Field):
        # 自定義的char類型的字段類
        def __init__(self, max_length, *args, **kwargs): #init能夠自定義,不寫源碼裏面也有
            self.max_length = max_length
            super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)
    
        def db_type(self, connection):
            #限定生成數據庫表的字段類型爲char,長度爲max_length指定的值
            return 'char(%s)' % self.max_length
    
    #調用:
    phone = MyCharField(max_length=11)

字段參數

  • null=True 數據庫該字段能夠爲空

  • blank=True 校驗時能夠爲空,from表單能夠不填

  • default 默認值

  • unique 惟一索引,有重複的添加不了

  • verbose_name admin頁面顯示的名稱

  • choices=((True, '男'), (False, '女')) 可選擇的參數

    # 單選,經過bool進行設置,true爲1 false爲0,默認爲男1
    gender = models.BooleanField(default=True,choices=((True,'男'),(False,'女')))
    
    gender = models.BooleanField(max_length=32,choices=((1,'男'),(2,'女'),(3,'xxx')))

  • 其餘參數:

    • db_column 跟數據庫關聯時使用,關聯數據庫中的列名

    • db_index=True 數據庫字段建立索引

    • editable=False 不可編輯,默認爲True

    • help_text admin頁面顯示提示信息

表的參數

class Person(models.Model):
    pid  = models.AutoField(primary_key=True)  
    name = models.CharField(max_length=32,db_column='username',db_index=True)      
    age = models.IntegerField(null=True,blank=True,editable=False)  
    bith = models.DateTimeField(auto_now=True)  
    phone = MyCharField(max_length=11,null=True,blank=True)
    gender = models.BooleanField(default=True,choices=((True,'男'),(False,'女')))


    class Meta:
        db_table = "person"  #數據庫中生成表名稱 默認app名稱+下劃線+類名

        verbose_name = '我的信息'                # admin中顯示的表名稱
        verbose_name_plural = '全部用戶信息'      # admin中導航欄修改

        index_together = [
            ("name", "age"),                    # 聯合索引,兩個存在的字段
        ]

        unique_together = (("name", "age"),)    # 聯合惟一索引,不可重複

必會13條查詢語句:

  • 在文件中查詢引入配置:

    import os
    import django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled.settings")
    django.setup()
    from app01 import models

  • 查詢語句

    # all 獲取表中全部數據,結果是對象列表:QuerySet
    ret = models.Person.objects.all()
    
    
    # filter 獲取全部知足條件的數據,結果也是對象列表:QuerySet
    ret = models.Person.objects.filter(pk=1)
    
    
    # first和last 獲取第一個/最後一個 拿不到值爲none,結果爲對象
    ret = models.Person.objects.filter().first()
    
    
    # get 獲取到一個知足條件的數據,存在並且惟一,查不到或者多個報錯,結果是對象
    ret = models.Person.objects.get(pk=1)
    
    
    # exclude 獲取不知足條件結果,取反,結果是對象列表:QuerySet
    ret = models.Person.objects.exclude(pk=1)
    
    
    #order_by  按照字段排序,默認升序,降序爲'-pid',
    ret = models.Person.objects.all().order_by('pid')
    ret = models.Person.objects.all().order_by('age','-pid') #多個字段排序,先排前面
    
    
    #reverse 只能對已經排序的QuerySet進行翻轉
    ret = models.Person.objects.all().order_by('pid').reverse()
    
    
    #values  獲取對象的字段名和字段值,結果是對象列表:QuerySet,列表裏面爲字典
    ret = models.Person.objects.all().values()
    ret = models.Person.objects.all().values('pid','name')      #能夠指定字段
    ret = models.Person.objects.all().values_list('pid','name') #拿取字段值
    
    
    #distinct 只能是同樣的對象才能夠去重,distinct中不可填寫字段
    ret = models.Person.objects.all().distinct()            #只能去重相同對象
    ret = models.Person.objects.values('age').distinct()    #這樣能夠去重
    
    
    #count  計數
    ret = models.Person.objects.all().count()
    
    
    # exists 判斷數據是否存在,結果爲布爾值
    ret = models.Person.objects.filter(pk=1).exists()
    print(ret)
    
    返回queryset:all filter exculde values(字典) values_list()  order_by reverse distinct
    返回對象:get first last
    返回布爾值:exists
    返回數字:count

  • 單表的雙下劃線(字段__過濾條件)

    • 大於小於

      ret = models.Person.objects.filter(pk__gt=1)    #id大於1(greater than)
      ret = models.Person.objects.filter(pk__lt=5)    #id小於5(less than)
      ret = models.Person.objects.filter(pk__gte=1)   #id大於等於1 (greater than equal)
      ret = models.Person.objects.filter(pk__lte=5)   #id小於等於5 (greater than equal)

    • 查詢範圍

      ret = models.Person.objects.filter(pk__range=[1,3])
      ret = models.Person.objects.filter(pk__in=[1,3,5])   #in 查詢多個

    • 模糊查詢(like),查當前字段中有g的數據

      ret = models.Person.objects.filter(name__contains='g')    #查詢包含g的字段
      ret = models.Person.objects.filter(name__icontains='g')   #ignore 忽略大小寫
      
      ret = models.Person.objects.filter(name__startswith='h')  #查詢以h開頭的
      ret = models.Person.objects.filter(name__istartswith='h') #ignore 忽略大小寫
      
      ret = models.Person.objects.filter(name__endswith='g')    #查詢以g結尾的
      ret = models.Person.objects.filter(name__iendswith='g')   #ignore 忽略大小寫

    • 查詢時間

      ret = models.Person.objects.filter(bith__year='2020')        #查看年份
      ret = models.Person.objects.filter(bith__contains='09')      #查看月份
      ret = models.Person.objects.filter(bith__contains='2019-09') #查看年月

    • 查詢爲空數據

      ret = models.Person.objects.filter(age__isnull=True)

外鍵查詢:

  • 對象正向查詢

    #外鍵的正常查詢能夠取到書籍是哪一個出版社出版的
    
    book_obj = models.Book.objects.get(pk=1)
    print(book_obj)            #關聯的對象
    print(book_obj.pub_id)       #關聯的對象的id
    print(book_obj.pub.name)       #關聯的對象的id,經過書籍查詢到出版社

  • 對象反向查詢

    pub_obj = models.Publisher.objects.get(pk=1)
    
    print(pub_obj.name)               #當前出版社
    print(pub_obj.book_set)         #關係管理對象   不指定related_name
    print(pub_obj.book_set.all())   #關聯的全部對象,根據出版社ID查詢書籍
    
    
    # 外鍵 related_name
    publisher = models.ForeignKey(to="Publisher", related_name='books')
    print(pub_obj.book.all())       #在models中指定related_name,替換book_set

  • 基於字段查詢

    #表中有外鍵的話,直接經過外鍵__字段
    ret = models.Book.objects.filter(pub__name="沙河出版社")       #__跨表查詢,根據出版社拿書
    ret = models.Book.objects.filter(pub__name__contains="沙河") 
    
    
    #表中沒有外鍵,直接經過表名__字段
    ret = models.Publisher.objects.filter(book__title='神鵰俠侶')  #根據書拿出版社
    
    
    #指定related_name 使用類名小寫,related_query_name='book' 後面覆蓋前面
    ret = models.Publisher.objects.filter(books__title='神鵰俠')

外鍵關係管理對象:

  • SET不可用,set不能經過ID添加,只能添加對象

  • add

    #外鍵添加數據,修改書籍的出版社
    pub_obj = models.Publisher.objects.get(pk=1)
    pub_obj.book_set.add(*models.Book.objects.filter(pk__in=[2,4,6]))
  • remove

    #外鍵刪除,字段要爲空
    pub_obj.book_set.remove(*models.Book.objects.filter(pk__in=[2,4,6]))
  • clear

    pub_obj.book_set.clear()    #清空
  • create

    pub_obj.book_set.create(title='小白',pub_id=2)  #添加書籍和出版社,不填默認本身1

多對多

  • 對象正向查詢(跟外鍵使用方法同樣)

    auth_obj = models.Author.objects.get(pk=1)
    
    print(auth_obj.name)
    print(auth_obj.books)          #關聯管理對象
    print(auth_obj.books.all())    #關聯對象      經過做者找書籍

  • 對象反向查找(跟外鍵使用方法同樣)

    book_obj = models.Book.objects.get(pk=1)
    
    print(book_obj.title)
    print(book_obj.author_set)         #關聯管理對象
    print(book_obj.author_set.all())   #關聯對象   經過書籍找做者

  • 基於字段查詢

    ret = models.Book.objects.filter(author__name='俊麗')         #經過做者找書名
    
    ret = models.Author.objects.filter(books__title='少有人走的路')  #經過書名找做者

多對多關係管理對象

  • set:添加以前會刪除清空

    author_obj = models.Author.objects.get(pk=1)
    
    author_obj.books.set([1,2])    #set [存放的是關聯的ID,能夠是多個],以前的會覆蓋掉
    author_obj.books.set(models.Book.objects.filter(pk__in=[1,2]))   #set [也能夠是對象]

  • add :新增新的關係,以前不變,重複添加以前的也不變

    # add添加是不會覆蓋刪除,而是新增
    author_obj = models.Author.objects.get(pk=1)
    
    author_obj.books.add(3)     #添加ID
    author_obj.books.add(models.Book.objects.get(pk=4))            #添加對象
    author_obj.books.add(*models.Book.objects.filter(pk__in=[3,4]))  #添加多個對象,*打散

  • remove 刪除

    author_obj = models.Author.objects.get(pk=1)
    
    author_obj.books.remove(2)   #跟add語法同樣
    author_obj.books.remove(*models.Book.objects.filter(pk__in=[3,4]))

  • clear 清空

    # 將關係所有清空
    author_obj = models.Author.objects.get(pk=1)
    
    author_obj.books.clear()

  • create 新增

    #給做者添加書籍和出版社
    author_obj = models.Author.objects.get(pk=2)
    author_obj.books.create(title='小紅書',pub_id=1)  #經過做者2對象,添加一本小紅書和出版社1的id
    
    #給書籍添加做者
    book_obj = models.Book.objects.get(pk=2)
    book_obj.author_set.create(name='小黑')          #先查找書籍,在經過書籍對象反向寫入做者

聚合

  • 引入聚合函數
    from django.db.models import Max,Min,Count,Avg,Sum
  • aggregate

    #統計書中最高的價格,整個字段,aggregate爲終止方法,後面不可在添加方法了
    ret= models.Book.objects.aggregate(max=Max('price'),min=Min('price'))
    
    #先進行篩選,選擇範圍以後在使用聚合函數
    ret=models.Book.objects.filter(pk__range[3,7]).aggregate(max=Max('price'),min=Min('price'))
    
    print(ret['max'])   #返回的是字典,使用key來取值

分組

  • 統計每一本數的做者個數

    #book:按照book_id進行分組  annotate:填寫聚合函數(將count結果註釋到Book中)
    
    ret = models.Book.objects.annotate(count=Count('author')).values()
    for i in ret:
        print(i)
  • 統計出每一個出版社的最便宜書的價格 分組聚合

    # 方法一
    # 先使用出版社進行分組,annotate註釋 填寫聚合函數,將結果寫入對象中,以出版社爲準
    ret= models.Publisher.objects.annotate(min=Min('book__price')).values()
    
    for i in ret:
        print(i['min'])
    
    
    # 方法二!!!
    #values分組條件    #以書籍爲準
    ret = models.Book.objects.values('pub__id').annotate(min=Min('price'))
    
    for i in ret:
        print(i['min'])
  • 統計不止一個做者的圖書-篩選

    # 先分組聚合,以後進行篩選
    ret = models.Book.objects.annotate(count=Count('author')).filter(count__gt=1)
    
    for i in ret:
        print(i.title)
  • 根據做者數量,進行-排序

    # 先分組聚合,以後排序
    ret = models.Book.objects.annotate(count=Count('author')).order_by('-count')
    
    for i in ret:
        print(i.title)
  • 查詢各個做者書的總價格

    #第一種方法:經過做者分組,反向取price   以做者表進行左鏈接
    ret = models.Author.objects.annotate(sum=Sum('books__price'))
    
    for i in ret:
        print(i.name,i.sum)
    
    
    #第二種方法:經過做者分組,在經過錢來取值   以書進行左鏈接,因此會出現none狀況
    ret = models.Book.objects.values('author').annotate(sum=Sum('price'))
    for i in ret:
        print(i
    
    #轉成sql過程
    1.先把book表和authro進行left join連表
    2.連完表以後進行group by分組
    3.以後再進行函數取值

F和Q

  • save和update字段區別:

    • save會所有都保存一遍

    • update會只針對查詢的數據進行保存,!!!

  • F 兩個字段比較,跟子查詢很像

    F兩個字段進行比較(裏面不能進行聚合和models,只能使用字段)

    from django.db.models import F
    
    #sale字段大於(gt)num字段的有哪些
    ret = models.Book.objects.filter(sale__gt=F('num')) 
    
    #篩選book表pk字段等於1,針對這個行數據的sale進行修改
    ret = models.Book.objects.filter(pk=1).update(sale=F('sale') *2 + 10)

  • Q 或與非

    from django.db.models import F,Q
    ret = models.Book.objects.filter(Q(pk__gt=5)|Q(pk__lt=2))  #大於5或者小於2
    
    ret = models.Book.objects.filter(~Q(pk__gt=5)&Q(pk__lt=2)) #與
    
    ret = models.Book.objects.filter(~Q(pk__gt=5)|Q(pk__lt=2)) #小於等於5或者小於2(~非)
    
    ret = models.Book.objects.filter(Q(~Q(pk__gt=5)&Q(pk__lt=2))|Q(pk__lt=2)) #設置多個匹配

事務

  • 事務把一系列操做,多是多條的,我去執行,要麼成功要麼都失敗,當出現問題所有都要回滾回去,保證原子性

    # 驗證事務
    from django.db import transaction
    try:
        with transaction.atomic():
            book1 = models.Book.objects.get(pk=1)
            book2 = models.Book.objects.get(pk=2)
    
            book1.num -=50
            book1.save()
    
            int("sssss")  #默認是有事務,try int的錯誤
    
            book2.num += 50
            book2.save()
    except Exception as  e:
        print(e)

  • cookie就是保存在瀏覽器上的一組鍵值對,這個鍵值對是服務器發送出來存儲在瀏覽器上,當瀏覽器在訪問服務器時,會自動攜帶這些鍵值對,服務器接受後能夠利用處理這些鍵值對

  • 爲何要有cookie:HTTP協議是沒有狀態的,每次請求都是獨立的,不會受前面的結果影響

cookies和session區別:

  • 應爲http自己是無狀態的,因此使用cookies和session都是用來記錄客戶端的狀態

  • cookies是以文本鍵值對存儲在瀏覽器中,session是存儲在服務端
  • cookies的存儲數量有限只有4kb,而session是無限量的
  • 還有就是安全問題,咱們能夠輕鬆訪問到cookie值,可是咱們沒法直接訪問會話值,所以session更安全

原理

  • 首先客戶端向服務端發送一個post請求,提交帳號密碼

  • 服務器校驗帳號密碼,正確向瀏覽器寫入登陸成功狀態

  • 瀏覽器再次請求時,會自動攜帶cookie的狀態在發送給服務器,服務器在判斷狀態

  • 特性:

    • 服務器讓瀏覽器進行設置的,鍵值對保存在瀏覽器

    • 瀏覽器下次訪問事自動攜帶對應的cookie

  • 應用:

    • 登錄,記錄登陸狀態

    • 投票,投票記錄狀態

    • 記錄網頁的瀏覽習慣,分頁多少條數據

django中操做cookies

  • 設置

    #設置cookie  Set-Cookie: is_login=1; 添加響應頭
    ret.set_cookie('is_login','1000') 
    
    
    #設置加密的cookie Set-Cookie: is_login=1
    ret.set_signed_cookie('is_login', '1000', '鹽')

  • 獲取

    is_login = request.COOKIES.get('is_login')  #讀取cookies
      if is_login != '1000':                  #判斷是否有cookies
    
    #獲取加密鹽的cookie    
    request.get_signed_cookie('is_login',default='',salt='鹽')   #獲取不到值,設置一個默認值

  • 刪除

    def logout(request):            
        ret = redirect('/login/')
        ret.delete_cookie('is_login')   #刪除cookie
        return ret

參數:

  • key, 鍵 value='', 值

  • expires=None, IE 瀏覽器的超時時間

  • max_age=None 瀏覽器超時時間,沒有設置瀏覽器關閉就失效

    ret.set_signed_cookie('is_login', '1000', '鹽',max_age=10)  #超過10秒cookei失效!!
  • path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問

    #針對某個目錄設置cookie地址,沒有cookie不能訪問
    ret.set_signed_cookie('is_login', '1000', '鹽',path='/home/')
  • domain=None, Cookie生效的域名,默認對全部域名生效

  • secure=False, https傳輸 爲true是有爲https協議時候才傳輸cookei

  • httponly=False 只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)

Cookie應用示例:

  • 網頁登陸:

    from django.shortcuts import render,redirect,HttpResponse
    
    def login_required(func):
        def inner(request,*args,**kwargs):
            # is_login = request.COOKIES.get('is_login')  #讀取cookies
            is_login =  request.get_signed_cookie('is_login', default='', salt='鹽')
    
            if is_login != '1000':                    #沒cookies執行login,url上添加當前路徑
                 return redirect(f'/login/?returnurl={request.path_info}')
    
            ret = func(request,*args,**kwargs)      #執行home或者index
            return ret
        return inner
    
    
    def login(request):
         if request.method == "POST":
             user = request.POST.get('user')
             pwd = request.POST.get('password')
    
             if user == 'haiyang' and pwd =='123':          #效驗登陸狀態
                 returnurl = request.GET.get('returnurl')   #獲取是否有要跳轉的地址
                 if returnurl:
                     ret = redirect(returnurl)
                 else:
                     ret = redirect('/home/')               #登陸成功要調轉的地址
    
        # ret.set_cookie('is_login','1000')  #設置cookie  Set-Cookie: is_login=1; 添加響應頭
                 ret.set_signed_cookie('is_login', '1000', '鹽',path='/home/')
                 return ret
    
             return render(request,'login.html',{'error':'用戶名錯誤'})  #密碼錯誤返回
         return render(request,'login.html')
    
    
    @login_required                       #訪問home頁面調用裝飾器
    def home(request):                      #home頁面
        return HttpResponse("home ok")
    
    @login_required
    def index(request):                     #index頁面
        return HttpResponse("index ok")
    
    def logout(request):                  #刪除cookie
        ret = redirect('/login/')
        ret.delete_cookie('is_login')
        return ret
    
    
    #前端代碼
    <form action="" method="post">
        {% csrf_token %}
        <p>用戶名:<input type="text" name="user"></p>
    
        <p>密碼:<input type="text" name="password"></p>
    
        <p style="color: red">{{ error }}</p>
        <button>登陸</button>
    </form>

session

  • session會話控制,保存在服務器上一組組鍵值對 ,可是必須依賴於cookie。

  • 爲何session要就與cookie,沒有cookie,創建鏈接就生成一個session_id,那麼打開幾個頁面就是幾個session,使用cookie就能夠把session_id保存在cookie中,每次訪問攜帶

  • 爲何要用session

    • session保存在服務器上,安全

    • cookie 保存在瀏覽器上 不安全

    • 瀏覽器對cookie的大小有限制

  • session原理圖

    session原理

  • session流程:

    • 首先客戶端向服務端發送一個post請求,提交帳號密碼
    • 服務器校驗帳號密碼,效驗正確,向瀏覽器返回
    • 瀏覽器再次請求時,會自動攜帶session_id發送給服務器,服務器經過session_id拿取到值

  • 數據庫中session標識

    • session表名:django_session

      • session_id

      • session_data

      • expire_date:超時時間,默認兩週

django中的操做:

  • 設置session

    request.session['is_login'] ='1000'  
    request.session['is_login1'] ='1000'      #能夠設置多個鍵值對
    
    request.session.setdefault('k1',123)      #存在則不設置
    
    del request.session['is_login']           #刪除鍵值對

  • 獲取

    #兩種獲取方式
    request.session.get('is_login')   
    
    request.session['is_login']
    
    #能夠當成字典使用
    request.session.keys()
    request.session.values()
    request.session.items()     #設置多個鍵值對能夠都取到

  • 刪除

    request.session.delete()   # 刪除session 數據 不刪除cookie
    request.session.flush()    # 刪除session 數據 刪除cookie
    
    
    def logout(request):            #刪除session
        ret = redirect('/login/')
        request.session.flush()
        return ret

  • session方法:

    request.session.session_key            #拿到數據庫中的key
    
    request.session.clear_expired()        #將全部Session失效日期小於當前日期的數據刪除
    
    request.session.exists("session_key")  # 檢查會話session的key在數據庫中是否存在
    
    
    request.session.set_expiry(value)      # 設置會話Session和Cookie的超時時間
        * 若是value是個整數,session會在些秒數後失效。
        * 若是value是個datatime或timedelta,session就會在這個時間後失效。
        * 若是value是0,用戶關閉瀏覽器session就會失效。
        * 若是value是None,session會依賴全局session失效策略。

  • session設置:

    #查看session配置 在settings中設置 from django.conf import global_settings
    
    #每次訪問保存session,默認爲flase 設置後在兩週內在此訪問,延長兩週
    SESSION_SAVE_EVERY_REQUEST = True
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False  #關閉瀏覽器cookie就失效了
    
    1. 數據庫Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)
    
    2. 緩存Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置
    SESSION_CACHE_ALIAS = 'default'                            
    
    3. 文件Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() 
    SESSION_FILE_PATH = None                                    
    
    
    4. 緩存+數據庫
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
    
    5. 加密Cookie 把Session數據放在cookie裏
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
    
    
    其餘公用設置項:
    SESSION_COOKIE_NAME = "sessionid"           
    # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
    SESSION_COOKIE_PATH = "/"                   # Session的cookie保存的路徑(默認)
    SESSION_COOKIE_DOMAIN = None                 # Session的cookie保存的域名(默認)
    SESSION_COOKIE_SECURE = False                # 是否Https傳輸cookie(默認)
    SESSION_COOKIE_HTTPONLY = True               # 是否Session的cookie只支持http傳輸(默認)
    SESSION_COOKIE_AGE = 1209600                 # Session的cookie失效日期(2周)(默認)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False      # 是否關閉瀏覽器使得Session過時(默認)
    SESSION_SAVE_EVERY_REQUEST = False     # 是否每次請求都保存Session,默認修改以後才保存(默認)

session代碼示例:

  • 網頁登陸

    from django.shortcuts import render,redirect,HttpResponse
    
    def login_required(func):
        def inner(request,*args,**kwargs):
    
            is_login = request.session.get('is_login') # 經過session去數據庫中拿取key
            print(is_login)
            if is_login != '1000':     #沒session執行login,url上添加當前路徑
                 return redirect(f'/login/?returnurl={request.path_info}')
    
            ret = func(request,*args,**kwargs)          #執行home或者index
            return ret
        return inner
    
    
    def login(request):
        request.session.clear_expired()  # 設置清除已經失效的session數據
        if request.method == "POST":
             user = request.POST.get('user')
             pwd = request.POST.get('password')
    
             if user == 'haiyang' and pwd =='123':        #效驗登陸狀態
                 returnurl = request.GET.get('returnurl')  #獲取是否有要跳轉的地址
                 if returnurl:
                     ret = redirect(returnurl)
                 else:
                     ret = redirect('/home/')              #登陸成功要調轉的地址
    
                 #設置session,使用cookie將session_id結果傳給瀏覽器
                 request.session['is_login'] = '1000'
                 request.session.set_expiry(10)                          #設置超時時間
                 return ret
    
             return render(request,'login.html',{'error':'用戶名錯誤'}) #密碼錯誤返回
        return render(request,'login.html')
    
    
    
    @login_required
    def home(request):
        return HttpResponse("home ok")
    
    @login_required
    def index(request):
        return HttpResponse("index ok")
    
    
    def logout(request):                   #刪除session
        ret = redirect('/login/')
        request.session.delete()
        return ret

中間件

  • django的中間件是用來處理django請求和響應,框架級別的鉤子(相似於裝飾器,添加新的內容),他是一個輕量,低級別的插件系統,也就是,我是用插件就改變,每一箇中間件組件都負責作一些特定的功能

  • 添加插件,影響的是全局,謹慎使用,使用不當會影響性能,注意

  • django中間件就是一個類,五個方法,四個特色

定義中間件

  • settings 中間件配置

    • 配置中註冊APP

      MIDDLEWARE = [
          'django.middleware.security.SecurityMiddleware',
          'django.contrib.sessions.middleware.SessionMiddleware', #中間件沒有返回值走下面
          'app01.mymiddleware.MD1',
          'app01.mymiddleware.MD2',]
          #執行urls
          #執行視圖

process_request

  • 執行時間:

    • 在路由前面執行
  • 參數:

    • request:process_request中的request和views中接受的請求是同一個
  • 順序:

    • 多個process_request,按照中間件的註冊順序,順序執行
  • 返回值:

    • None:爲none是正常流程

    • HttpResponse:當前中間件中有return以後,路由匹配,視圖函數都不執行了,若是有response,直接執行當前中間件process_response的方法,倒序執行以前的process_response方法,最終返回給瀏覽器

process_response

  • 執行時間:

    • 在視圖函數後面執行
  • 參數:

    • request:process_request中的request和views中接受的請求是同一個
    • response:視圖返回的response對象
  • 順序:

    • 按照中間件的註冊順序,倒序執行
  • 返回值:

    • HttpResponse:必須return返回視圖的Response對象,返回值也能夠本身返回

      def process_response(self,request,response):  #response響應對象
              print("MD2 process_response")
              # return response
              return HttpResponse('ok98')

process_view

  • 執行時間:

    • 在路由匹配以後,視圖函數以前
  • 參數:request response:

    • request 請求都是同一個
    • view_func:視圖函數 (function index at 0x31435345242134)
    • view_args,:位置參數,urls中的分組信息
    • vies_kwargs:關鍵字參數,命名分組
  • 順序:

    • 按照中間件的註冊順序,順序執行
  • 返回值:

    • None:正常流程

    • HttpResponse:當前中間件以後的process_view不執行了,視圖函數都不執行了,倒序執行中間件中的process_response方法,最終返回給瀏覽器

process_exception

  • 執行時間:

    • 視圖層有錯誤異常觸發條件,執行
  • 參數:request response:

    • request 請求對象都是同一個
    • exception:錯誤對象
  • 順序:

    • 按照中間件的註冊順序,在視圖函數以後都是倒序執行
  • 返回值:

    • None:交給下一個中間件處理異常,全部的中間件都沒有處理的話,django最後進行處理

    • HttpResponse:中間件以前的process_exception不執行了,直接執行最後一個方法,倒序執行中間件中的process_response方法,最終返回給瀏覽器

process_template_response

  • 執行時間:

    • 視圖返回的reqponse是一個template_response 模板對象
  • 參數:request response:

    • request 請求都是同一個
    • response:響應對象
  • 順序:

    • 按照中間件的註冊順序,倒序執行
  • 返回值:

    • HttpResponse:必須返回process_template_response對象,返回的結果,以最後一個爲準,倒序執行中間件中的process_response方法,最終返回給瀏覽器

中間件示例

  • 代碼示例

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class MD1(MiddlewareMixin):
        def process_request(self,request):  #處理請求,request和views請求同樣
            print("MD1 process_request")
            # return HttpResponse("md1")
    
        def process_response(self,request,response):  #response響應對象
            print("MD1 process_response")
            return response
    
        def process_view(self,request,view_func,view_args,vies_kwargs):
            # print(view_func)
            # print(view_args)
            print("MD1 process_view")
            return HttpResponse("dudu")
    
        def process_exception(self,request,exception):
            print("MD1 process_exception")
            # return None
    
        def process_template_response(self,request,response):
            print("MD1 process_template_response")
            response.template_name = "index1.html"       #替換新的頁面
            response.context_data['user']='newhai'  #更改返回的數據
            return response
    
    
    class MD2(MiddlewareMixin):
        def process_request(self,request):  #處理請求,request和views請求同樣
            print("MD2 process_request")
    
        def process_response(self,request,response):  #response響應對象
            print("MD2 process_response")
            return response
    
        def process_view(self,request,view_func,view_args,vies_kwargs):
            print("MD2 process_view")
            return HttpResponse("xiix")
    
        def process_exception(self,request,exception):
            print("MD2 process_exception")
            # return HttpResponse("處理完了")
    
        def process_template_response(self,request,response):
            print("MD2 process_template_response")
            response.template_name = "index1.html"         #替換新的頁面
            response.context_data['user']='newhaiyang1'    #更改返回的數據
            return response
    
    
    #views
    from django.shortcuts import render,HttpResponse
    from django.template.response import TemplateResponse
    
    def index(request):
        print('indexa')
        # ret = HttpResponse("OK")
        # int("aaaaaa")
        # return ret
        return TemplateResponse(request,'index.html',{'uesr':'haiyang'})
    
    #urls
    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),]
    
    #template
    <body>
      <h1>index{{ uesr }}</h1>
    </body>

django-請求生命週期圖

  • 客戶端發送HTTP請求,wsgi接受http請求,將http請求封裝成request,傳送給process_request -->路由urls -->process_vies ---> 視圖 --->process-response

django請求流程圖

csrf

csrf裝飾器:

  • csrf_exempt,csrf_protect使用

    from django.shortcuts import render,redirect,HttpResponse
    
    from django.views.decorators.csrf import csrf_exempt,csrf_protect  #csrf裝飾器
    @csrf_exempt     #設置csrf,訪問不須要進行csrf校驗
    @csrf_protect    #不設置csrf,必需要進行校驗
    def form(request):
        return render(request,'form.html')
    
    
    #類中設置csrf
    from django.utils.decorators import method_decorator    #引入裝飾器
    from django.views import View
    
    
    @method_decorator(csrf_exempt,name='dispatch')
    class From(View):
        def get(self,request):
            return render(request,'form.html')
    
        def post(self,request):
            return render(request,'form.html')

csrf的中間件流程:

  • 查看中間件的方法:

    #找到中間件進行引用
    from django.middleware.csrf import  CsrfViewMiddleware

  • 想要能經過csrf校驗的前提條件 必需要有csrftoken 的cookie

    • 第一種:{% csrf_token %} 生成token

    • 第二種:from django.views.decorators.csrf import ensure_csrf_cookie

      @method_decorator(ensure_csrf_cookie)
      def get(self,request):

  • csrf流程:

    • 從cookie獲取csrftoken的值 與 POST提交的數據中的csrfmiddlewaretoken的值作對比

    • 若是從request.POST中獲取不到csrfmiddlewaretoken的值,會嘗試從請求頭中獲取x-csrftoken的值,而且拿這個值與csrftoken的值作對比,對比成功也能經過校驗。

  • 源代碼:

    class CsrfViewMiddleware(MiddlewareMixin):
    def _get_token(self, request):
            if settings.CSRF_USE_SESSIONS:   #第二步:判斷session是否爲flase
                try:
                    return request.session.get(CSRF_SESSION_KEY)  #獲取session
                except AttributeError:
            else:
                try: #第三部:獲取瀏覽器cookie對應的值
                    cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME] 
                except KeyError:
                    return None
    
                csrf_token = _sanitize_token(cookie_token) #第四步:調用_sanitize_token
                if csrf_token != cookie_token:             #判斷cookie是否匹配
                    request.csrf_cookie_needs_reset = True #cookie不相等,從新設置
                return csrf_token               #第五步返回token
    
    
    def _sanitize_token(token):             #判斷cookie是否符合
        if re.search('[^a-zA-Z0-9]', force_text(token)):
            return _get_new_csrf_token()      #匹配token,獲取到新的token
        elif len(token) == CSRF_TOKEN_LENGTH: #匹配長度是64的直接返回
            return token
        elif len(token) == CSRF_SECRET_LENGTH:
            return _salt_cipher_secret(token)
        return _get_new_csrf_token()
    
    
    def process_request(self, request):
      #第一步:調用_get_token函數,從cookie中獲取csrftoken的cookie值
      csrf_token = self._get_token(request)  
      if csrf_token is not None:
          request.META['CSRF_COOKIE'] = csrf_token  #有結果,將獲取的cookie值放在請求頭部信息
    
    
    def process_view(self, request, callback, callback_args, callback_kwargs):
      #csrf_processing_done等於true 返回none view爲none正常流程
        if getattr(request, 'csrf_processing_done', False): 
            return None
    
      #在viws中函數加入csrf_exempt,值就會給true
        #callback從函數裏面拿csrf_exempt豁免,若是等於true返回none,      
      if getattr(callback, 'csrf_exempt', False):
            return None
    
      #不是這些請求的話返回,是post del
      if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
          return self._accept(request)  #self._accept 處理完成等於true返回none,正常流程
    
            #不須要進行強制性效驗
            if getattr(request, '_dont_enforce_csrf_checks', False):
    
            if request.is_secure():   #若是發的是https請求
            csrf_token = request.META.get('CSRF_COOKIE')#以前代碼添加的,從字典裏面獲取cookie值
    
            if csrf_token is None:    #若是請求csrf_token沒有值403
              return self._reject(request, REASON_NO_CSRF_COOKIE)
    
            request_csrf_token = ""
          if request.method == "POST": #若是是post請求
              #獲取瀏覽器頁面post提交的數據
              request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
    
          #比較加密過的數據是否效驗成功
          if not _compare_salted_tokens(request_csrf_token, csrf_token):
                    return self._reject(request, REASON_BAD_TOKEN)
    
          #從請求頭中獲取x-csrf_token,賦值html post數據
          if request_csrf_token == "":
              request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
      return self._accept(request)

ajax

  • 簡介:
    • JAX(Asynchronous Javascript And XML)翻譯成中文就是「異步的Javascript和XML」。即便用Javascript語言與服務器進行異步交互,傳輸的數據爲XML(固然,傳輸的數據不僅是XML)。

  • ajax

  • js技術,給服務發送請求。

  • 特色: 異步(發送請求,不等待結果)傳輸的數據量小 局部刷新(輸入框返回來的不存在信息)

  • ajax請求方式:

    • 同步交互:客戶端發出一個請求後,須要等待服務器響應結束後,才能發出第二個請求
    • 異步交互:客戶端發出一個請求後,無需等待服務器響應結束,就能夠發出第二個請求

  • 請求方式-同步請求,發送一個請求,等待響應,在發送下一個

    • 瀏覽器地址欄輸入地址 get

    • a標籤 get

    • form表單 get/post

發送請求:

  • 發送代碼示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        {% load static %}
    </head>
    
    <body>
        <input type="text" name="i1">+
        <input type="text" name="i2">=
        <input type="text" name="i3">
        <button id="b1">計算</button>
        <script src="{% static 'jquery-3.4.1.js' %}"></script>  #使用ajax 引用js
    
        <script>
            $('#b1').click(function () {
                //發ajax請求
                $.ajax({
                    url: '/calc/',    #發送請求地址
                    type: 'post',     #請求方式,默認get
                    data:{            #發送的數據
                        'x1':$('[name="i1"]').val(),
                        'x2':$('[name="i2"]').val(),
                    },
                    success:function (res) {   #成功響應後的回調函數,res views響應return的數據
                        {#$('[name="i3"]').val(res)#}
                        location.href=res      #前端跳轉配置
                    }
                })
            })
        </script>
    </body>
    </html>     
    
    
    #urls
    urlpatterns = [
        url(r'^calc/', views.calc),
    ]
    
    #views
    def calc(request):
        i1 = request.POST.get('x1')
        i2 = request.POST.get('x2')
        return HttpResponse(i3)     
    
    
    #html
        <button id="b2">參數的測試</button>
          <script>
            $('#b2').click(function () {
                //發ajax請求
                $.ajax({
                    url: '/test/',
                    type: 'post',
                    data:{
                        'name':'haiyang',
                        'age':28,
                        {#'hobby':['檯球','吃飯','俊麗']#}
                        'hobby':JSON.stringify(['檯球','吃飯','俊麗'])
                    },
                    success:function (res) {
                        {#console.log(res)#}
                        console.log(res.status)
                    },
                    error:function (res) {
                        console.log(res)
                        location.href=res    #前端定義跳轉月面,res爲後端傳送的路徑
                    }
                })
            })
          </script>

使用json傳值

import json
def test(request):
print(request.POST)
# hobby = request.POST.getlist('hobby[]')
hobby = json.loads(request.POST.get('hobby'))
print(hobby,type(hobby))
# return HttpResponse("ok")
# int("aaa") #錯誤時候調用
return JsonResponse({'status':'ok','msg':'xxx'}) #迴應請求頭,變成對象

```

使用ajax上傳文件

  • 上傳文件代碼示例;

    ```js
    <!DOCTYPE html>



    Title
    {% load static %}

    urls

    urlpatterns = [
    url(r'^upload/', views.upload),]

    views

    def upload(request):
    f1 = request.FILES.get('f1')

    with open(f1.name,'wb') as f:
        for i in f1.chunks():
            f.write(i)
    
    return JsonResponse({'status': '上傳成功'})  # 迴應請求頭,變成對象

    瀏覽器訪問信息:

    Content-Type: multipart/form-data; boundary=----WebKitFormBoundarygNy1hssp07PGlGbq

    Form Data
    filname: xx
    f1: (binary)

```

ajax經過django的csrf校驗的方式

  • 第一種方法:給post,data中加csrfmiddlewaretoken鍵值對,與瀏覽器中獲取的csrfcookie對比

    data:{
        'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val(),
        'x1':$('[name="i1"]').val(),
        'x2':$('[name="i2"]').val(),
    },
    
    #瀏覽器查詢
    Form Data
    csrfmiddlewaretoken: VAfy6g35ZvuEh30J0wmKv9wNd02jlZkOetmPJ4PxpbQyv8IgAIXR4CnzPbzXNKT6
  • 第二種方法:data中加請求頭 x-csrftoken鍵值對

    headers:{
        'x-csrftoken':$('[name="csrfmiddlewaretoken"]').val(),
    },
  • 自定義ajax所有添加

    #在status中建立文件,本身寫一個getcookie方法
    
    function getCookie(name) {  #給cookie名字按照格式分隔開
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');  #調用函數,返回具體值
    
    
    function csrfSafeMethod(method) {        #請求匹配
      // these HTTP methods do not require CSRF protection
      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); #若是請求爲POST 返回True
    }
    
    $.ajaxSetup({    #給全局的ajax進行配置
      beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);  #爲post設置請求頭
        }
      }
    });
    
    #在html文件中導入引用
    <script src="{% static 'ajax_setup.js' %}"></script>

sweetalert:

  • 代碼示例:

    #引入sweetalert
    <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
    
    <button id='del' class="btn btn-primary btn-danger" url='/student_del/?pk={{ obj.id }}'>刪除</button>
    
    
    <script>
        $('.btn-danger').click(function () {   #獲取按鈕class觸發
            swal({
                title: "你肯定要刪除嗎?",
                text: "刪除可就找不回來了哦!",
                icon: "warning",
                buttons: true,
                dangerMode: true,
            })
                .then((willDelete) => {
                    if (willDelete) {
                        $.ajax({
                            url:  $(this).attr('url'),    #獲取del中url信息,傳到後端
                            success: (res) => {
                                if (res) {
                                    $(this).parent().parent().remove();
                                    swal("刪除成功!", "你能夠準備跑路了!", {
                                        icon: "success",
                                    });
                                } else {
                                    swal("刪除失敗", "你能夠再嘗試一下!", "error")
                                }
                            }
                        })
    
                    } else {
                        swal("你的選擇很正確!");
                    }
                });
        })
    </script>

Form表單

  • 經常使用的字段:

    CharField             #input
    ChoiceField         #select
    MultipleChoiceField   #多選
    DecimalField        #時間
    ModelMultipleChoiceField  #可選數據放入數據庫,每次刷新頁面都會從新查詢
    MultipleChoiceField       #單選
    
    #具體代碼見視圖標註
  • 字段內的參數:

    initial          #初始值
    label          #中文提示
    error_messages   #錯誤提示
    min_length       #最小長度
    max_length         #最大長度
    choices          #可選擇的值
    widget           #更改插件樣式 
    PasswordInput    #隱藏密碼
    disabled       #爲true不可編輯
    
    #具體代碼見視圖標註

視圖:

from django import forms

def check_user(value):    #自定義效驗,寫函數
    if 'haiyang' in value:
        raise ValidationError('haiyang 不能註冊')

from django.core.validators import validate_email,RegexValidator  #內置的效驗方法

class RegForm(forms.Form):
    #CharField文本輸入框,disabled=True不可編輯,validators填寫自定義的效驗和內置的效驗方法
    user = forms.CharField(label='用戶名',initial='胡海洋',validators=[validate_email])
    pwd  = forms.CharField(          #PasswordInput密碼框
        label='密碼',                 #label 輸入款前的提示
        widget=forms.PasswordInput,  #隱藏密碼
        required=True,               #默認是true,爲false不用填寫,不校驗
        min_length=6,
        max_length=12,
        error_messages={             #根據設置屬性,修改錯誤提示
            "required":'該字段是必需要填寫',
            'min_length':'密碼最少是6位',
            'max_length':'長度過長'
        })
    
    re_pwd  = forms.CharField(        #PasswordInput密碼框
        label='確認密碼',              #label 輸入款前的提示
        widget=forms.PasswordInput,   #隱藏密碼
        required=True,                #默認是true,爲false不用填寫,不校驗
        min_length=6,
        max_length=12,
        error_messages={             #根據設置屬性,修改錯誤提示
            "required":'該字段是必需要填寫',
            'min_length':'密碼最少是6位',
            'max_length':'長度過長'
        })
    
    gender = forms.ChoiceField(         #ChoiceField單選
        label='性別',
        choices=((1,'男'),(2,'女'),(3,'xx')),
        widget=forms.RadioSelect        #更改樣式
    )
    # hobby = forms.MultipleChoiceField(         #MultipleChoiceField多選
    #     label='愛好',
    #     initial=[1,2],                         #initial默認選擇多個
    #     # choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
    #     widget=forms.CheckboxSelectMultiple    #好用鼠標勾選
    # )

    hobby = forms.ModelMultipleChoiceField(  #多選|forms.MultipleChoiceField單選
        label='愛好',
        initial=[1,2],
        queryset=models.Hobby.objects.all(),  
        widget=forms.CheckboxSelectMultiple
    )
    birth = forms.DecimalField()


def reg2(request):
    from_obj = RegForm()              #對象實例化

    if request.method == 'POST':
        from_obj = RegForm(data=request.POST)   #POST又實例化一次
        if from_obj.is_valid():       #作校驗
            return HttpResponse('OK')

    return render(request, 'reg2.html',{'from_obj':from_obj})  #將對象傳給前端

模板:

{{ form_obj.as_p }}               # 展現全部的字段
{{ form_obj.user }}               # input框
{{ form_obj.user.label }}         # label標籤的中文提示,用戶名
{{ form_obj.user.id_for_label }}  # input框的id user
{{ form_obj.user.errors  }}       # 一個字段的錯誤信息
{{ form_obj.user.errors.0  }}     # 一個字段的第一個錯誤信息
{{ form_obj.errors  }}            # 全部字段的錯誤


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
<form action="" method="post" novalidate>
    {% csrf_token %}
    <p>
        <label for="{{ from_obj.user.id_for_label }}">{{ from_obj.user.label }}:</label>
        {{ from_obj.user }} <span>{{ from_obj.user.errors.0 }}</span>
    </p>

    <p>
        <label for="{{ from_obj.pwd.id_for_label }}">{{ from_obj.pwd.label }}:</label>
        {{ from_obj.pwd }}  <span>{{ from_obj.pwd.errors.0 }}</span>
    </p>

    <p>
        <label for="{{ from_obj.re_pwd.id_for_label }}">{{ from_obj.re_pwd.label }}:</label>
        {{ from_obj.re_pwd }}  <span>{{ from_obj.re_pwd.errors.0 }}</span>
    </p>

    <p>
        <label for="{{ from_obj.gender.id_for_label }}">{{ from_obj.gender.label }}:</label>
        {{ from_obj.gender }}  <span>{{ from_obj.gender.errors.0 }}</span>
    </p>

    <p>
        <label for="{{ from_obj.hobby.id_for_label }}">{{ from_obj.hobby.label }}:</label>
        {{ from_obj.hobby }}  <span>{{ from_obj.hobby.errors.0 }}</span>
    </p>

    <p>
        <label for="{{ from_obj.phone.id_for_label }}">{{ from_obj.phone.label }}:</label>
        {{ from_obj.phone }}  <span>{{ from_obj.phone.errors.0 }}</span>
    </p>

{#    {{ from_obj.errors }}#}
    <button>註冊</button>

</form>
</body>
</html>

校驗

required     #前端輸入字段是瀏覽器自動添加的required,post後面添加novalidate去除效驗
min_length   #校驗字段長度

自定義的校驗:

  • 寫函數:

    from django.core.exceptions import ValidationError
    
    def check_user(value):
      # 經過校驗   不作任何操做
      # 不經過校驗  拋出ValidationError異常 
        if 'haiyang' in value:
            raise ValidationError('haiyang 不能註冊')
    
    #在user字段中使用validators=列表中填寫效驗函數
    user = forms.CharField(label='用戶名',initial='胡海洋',validators=[check_user])

  • 使用內置的校驗器:

    #RegexValidator 使用內置效驗器過濾
    from django.core.validators import validate_email, RegexValidator
    
    phone = forms.CharField(validators=[RegexValidator(r'^1[3-9]\d{9}$','手機號格式不正確')])

  • is_valid流程:

    1. is_valid()中要執行full_clean():    #第一步、第四步
       1. self.is_bound data數據是否傳送 and self._errors ={}#第二步從新定義一個存放錯誤信息的字典 
       2. self.cleaned_data = {}         #第三步:定義一個存放有效的數據
    
    
    2. 執行self._clean_fields()           #第五步:清洗字段
       1. 先執行內置的校驗和校驗器的校驗      #第六步:
       2. 有局部鉤子,執行局部鉤子
    
    3. 執行 self.clean() 全局鉤子

局部鉤子和全局鉤子

#局部鉤子對當前字段進行效驗
    def clean_user(self):
    v = self.cleaned_data.get('user')
    # 局部鉤子
    # 不經過校驗 拋出異常
    # 經過校驗   必須返回當前字段的值
    if v =='haiyang':
        raise ValidationError("不配")
    return v

                
#全局部鉤子對所有字段進行效驗
from django.core.exceptions import ValidationError
def clean(self):
    # 全局鉤子
    # 不經過校驗 拋出異常
    # 經過校驗   必須返回全部字段的值 self.cleaned_data
    pwd = self.cleaned_data.get('pwd')
    re_pwd = self.cleaned_data.get('re_pwd')
    if pwd != re_pwd:
        self.add_error('re_pwd','兩次密碼不一致!')
        raise ValidationError('兩次密碼不一致')
    return self.cleaned_data
相關文章
相關標籤/搜索