Python之web框架Django

[TOC]css

1. web框架

HTTP協議

發送HTTP請求html

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

服務器接受請求並返回HTTP響應前端

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

在瀏覽器地址欄鍵入URL,按下回車以後經歷的過程node

1. 瀏覽器向DNS服務器請求解析該URL中的域名所對應的IP地址。
2. 解析出IP地址後,根據該IP地址和默認端口80,和服務器創建TCP鏈接。
3. 瀏覽器發出讀取文件(URL中域名後面部分對應的文件)的HTTP請求,該請求報文做爲TCP三次握手的第三次報文的數據發送給服務器
4. 服務器對瀏覽器做出響應,並把對應的html文本發送給瀏覽器
5. 釋放TCP鏈接
6. 瀏覽器渲染HTML並顯示內容

HTTP請求方法python

  • HTTP/1.1協議中共定義了八種方法(動做),來以不一樣方式操做指定的資源:
1. GET :
	向指定的資源發出"顯示"請求。使用GET方法應該只用在讀取數據上,而不該被用於產生"反作用"的操做中,例如在Web Application中,其中一個緣由是GET可能會被網絡蜘蛛等隨意訪問.
    
2. HEAD :
    與GET方法同樣,都是向服務器發出指定資源的請求。只不過服務器將不傳回資源的本文部分。它的好處在於,使用這個方法能夠在沒必要傳輸所有內容的狀況下,就能夠獲取其中「關於該資源的信息」(元信息或稱元數據)。
    
3. POST :
    向指定資源提交數據,請求服務器進行處理(例如提交表單或者上傳文件)。數據被包含在請求本文中。這個請求可能會建立新的資源或修改現有資源,或兩者皆有。
    
4. PUT :
    向指定資源位置上傳其最新內容。
   
5. DELETE :
    請求服務器刪除Request-URI所標識的資源。
    
6. TRACE :
    回顯服務器收到的請求,主要用於測試或診斷。
    
7. OPTIONS :
    這個方法可以使服務器傳回該資源所支持的全部HTTP請求方法。用'*'來代替資源名稱,向Web服務器發送OPTIONS請求,能夠測試服務器功能是否正常運做。
    
 8. CONNECT :
    HTTP/1.1協議中預留給可以將鏈接改成管道方式的代理服務器。一般用於SSL加密服務器的連接(經由非加密的HTTP代理服務器)
  • HTTP狀態碼mysql

    • 全部HTTP響應的第一行都是狀態行,依次是當前HTTP版本號,3位數字組成的狀態代碼,以及描述狀態的短語,彼此由空格分隔。
    1xx消息——請求已被服務器接收,繼續處理
    2xx成功——請求已成功被服務器接收、理解、並接受 :
      200 ok - 請求成功	
    3xx重定向——須要後續操做才能完成這一請求
    4xx請求錯誤——請求含有詞法錯誤或者沒法被執行 :
        403 Forbidden - 服務器已經理解請求,可是拒絕執行它
        404 Not Found - 請求失敗,請求所但願獲得的資源未被在服務器上發現。
    5xx服務器錯誤——服務器在處理某個正確請求時發生錯誤
  • URLweb

    • 超文本傳輸協議(HTTP)的統一資源定位符將從因特網獲取信息的五個基本元素包括在一個簡單的地址中:
    1. 傳送協議。
    2. 層級URL標記符號(爲[//],固定不變)
    3. 訪問資源須要的憑證信息(可省略)
    4. 服務器。(一般爲域名,有時爲IP地址)
    5. 端口號。(以數字方式表示,若爲HTTP的默認值「:80」可省略)
    6. 路徑。(以「/」字符區別路徑中的每個目錄名稱)
    7. 查詢。(GET模式的窗體參數,以「?」字符爲起點,每一個參數以「&」隔開,再以「=」分開參數名稱與數據,一般以UTF8的 	 URL編碼,避開字符衝突的問題)
    8. 片斷。以「#」字符爲起點
  • HTTP請求格式sql

    請求方法 | 空格 | URL | 空格 | 協議版本 | 回車符 | 換行符		--→ 	請求行
    
    頭部字段名 | : | 值 | 回車符 | 換行符 				 }
        		...									 }	--→   請求頭部
    頭部字段名 | : | 值 | 回車符 | 換行符 				 }
    
    !@#$%^&* ...										--→  請求數據
  • HTTP相應格式數據庫

    協議版本 | 空格 | 狀態碼 | 空格 | 狀態碼描述 | 回車符 | 換行符     --→ 	狀態行
    
    頭部字段名 | : | 值 | 回車符 | 換行符 				 }
        		...									 }	   --→   響應頭部
    頭部字段名 | : | 值 | 回車符 | 換行符 				 }
    
    請求方法 | 空格 | URL | 空格 | 協議版本 | 回車符 | 換行符		--→ 	響應正文

2. Django的使用

2.1. 本身寫的Web框架

mport socket

# 建立一個socket對象
sk = socket.socket()

# 綁定ip和端口
sk.bind(('127.0.0.1', 8848))

# 監聽
sk.listen()


def index(url):
    ret = '歡迎進入紅浪漫! - {}'.format(url)
    return ret.encode('utf-8')


def home(url):
    ret = '歡迎回家! - {}'.format(url)
    return ret.encode('utf-8')


def help_me(url):
    ret = '再等30年,你又是條好漢! - {}'.format(url)
    return ret.encode('utf-8')


list1 = [
    ('/index', index),
    ('/home', home),
    ('/help_me', help_me),
]

# 等待鏈接
while True:
    conn, addr = sk.accept()

    data = conn.recv(1024)
    url = data.decode('utf-8').split()[1]  # 獲取用戶輸入的路徑

    # for i in list1:
    #     if url == i[0]:
    #         ret = i[1](url)
    #         break
    # else:
    #     ret = '被查辦了!'.encode('utf-8')

    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()

2.2 Django的安裝

  • 命令行下載安裝django

    pip3 install django	 - 下載安裝的是最新版本
    pip3 install django==1.11.23 -i https://pypi.tuna.tsinghua.edu.cn/simple	- 選擇版本,選擇安裝源
    • 建立項目

      1. 首先進入要建立項目的文件夾
      2. SHIFT + 鼠標右鍵 打開命令行
      3. 執行命令 : django-admin startproject 項目名
    • 啓動項目

      python manage.py runserver	# 默認127.0.0.1 : 80000
      python manage.py runserver 80 # 修改 80端口
      python manage.py runserver 0.0.0.0:80 # 修改地址和端口
  • pycharm

    • 建立項目

      1. New Project
      2. Django - 選擇項目目錄 - 選python版本 - Create
    • 啓動項目

      選中項目目錄 - run(圖標)
    • pycharm建立項目的一些說明

      1. settings.py會在項目根目錄下自動建立一個名字爲 templates 用於放HTML等文件的文件夾 :
      	'DIRS': [os.path.join(BASE_DIR, 'templates')]
      2. 導入模塊 ( urls.py ):
         from django.shortcuts import HttpResponse,render
          def index(request):
              return HttpResponse('歡迎進入紅浪漫!')  #   返回字符串
          def home(request):
              return render(request,'home.html') # 返回html頁面
          urlpatterns = [
              url(r'^admin/', admin.site.urls),
              url(r'^home/', home),
              url(r'^index/', index),
          ]
      3. 修改ip和端口 :
      	Run → Edit Configurations

3. 靜態文件的配置

3.1. STATIC_URL配置

  • **項目中settings.py文件下 😗*

    STATIC_URL = '/static/'
    
    STATICFILES_DIRS = [    #按照列表的順序進行查找
        os.path.join(BASE_DIR,'static'),
        os.path.join(BASE_DIR,'xxx')
    ]
    
    
    os.path.join(BASEDIR, 'static', 'css')是靜態文件存放的實際路徑,STATIC_URL='/static/'中的/statis/是這個路徑的別名。二者是一個映射關係,若是要使用該靜態文件,那麼靜態文件的URL中的"實際路徑部分"就要使用別名來代替
    • settings.py配置好後, 須要在項目下新建文件static, 這個static是存放 CSS, JavaScript, Images等靜態文件的一個根目錄

4. 登陸驗證

form表單

form表單中 action 填寫提交表單的ip地址和端口 method 是提交請求方式 默認GET請求,html中要小寫
<form class="form-signin" action = "" method="post">
<input class="form-control" id="inputEmail" autofocus="" required="" type="email" placeholder="Email address" >

required="" 是表單的必填項,刪除後,就能夠了
<input class="form-control" id="inputEmail" autofocus="" required="" type="email" name="username" placeholder="Email address">
<input class="form-control" id="inputPassword" required="" type="password" name="password" placeholder="Password">
設置name的鍵值對
  • 關掉pycharm的校驗請求功能 - csrf 中間件

    在settings.py中
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
  • 禁用前端校驗

    form表單中添加 novalidate
    <form class="form-signin" action = "" method="post" novalidate>
  • urls.py 中校驗請求(用戶名密碼校驗)

    from django.shortcuts import HttpResponse, render, redirect
    
    
    def index(request):
        # 業務邏輯
        return HttpResponse('歡迎進入紅浪漫!')
    
    
    def home(request):
        return render(request, 'home.html')
    
    
    def login(request):
        if request.method == 'GET':
            # 返回登陸頁面
            return render(request, 'login.html')
        elif request.method == 'POST':
            # 獲取提交的數據 request.POST
            username = request.POST.get('username')
            password = request.POST.get('password')
            # 對用戶名和密碼進行校驗
            if username == 'alex' and password == 'alexdsb':
                # 校驗成功 跳轉到首頁(重定向)
                # return HttpResponse('歡迎進入紅浪漫!')
                return redirect('/index/')
            else:
                # 校驗失敗 從新登錄
                return render(request, 'login.html')

5. app

咱們在項目中的urls中配置路由,在templates 裏寫HTML文件,若是項目很大,路由不少,HTML文件不少,那麼就須要在項目的內部與與項目同名的同級建立APP應用,在APP應用裏能夠寫本身的urls和views 這樣主路由中的路由能夠映射到APP中的子路由,這個時候就像一個樹的根部到樹葉擴散。

建立app

CMD建立 :
進入項目文件夾下,按住shift右鍵進入命令行 :
	python manage.py startapp  app名稱

pycharm中 :
在Teminal命令行中鍵入命令 :
	python manage.py  startapp  app名稱
   
利用pycharm中的tools工具建立 :
    1. 調出窗口 : tools → Run manage.py Task ... 
    2. 鍵入命令 : startapp app名

註冊app

在settings中 :

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01',  # 第一種方式
    'app01.apps.App01Config', # 第二種方式  推薦寫法
]

app下的目錄解釋

admin.py   django admin 

​	apps.py  app的信息

​	models.py    模型  model  跟數據庫有關

​	views.py   寫函數(以前在urlspy中寫的函數寫在這裏

**將urls.py中的函數轉移到建立的app下的views.py 😗*

views.py下的全面內容

from django.shortcuts import render,redirect,HttpResponse

def login(requset):
    if requset.method == 'GET':
        # 返回登陸頁面
        return render(requset,'login.html')
    elif requset.method == 'POST':
        # 獲取提交的數據 (用戶名和密碼) 
        username = requset.POST.get('username')
        password = requset.POST.get('password')
        # 對用戶名和密碼進行校驗
        if username == 'python' and password == '123':
            # 校驗成功,跳轉到設置頁面(重定向)
            return redirect('http://donyz.s567.tw/')
        else:
            # 校驗失敗,從新登陸
            return render(requset,'login.html')

views.py中的函數導入到urls.py

urls.py文件下 :
    
from app01 import views  # 導入
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),  # 引用
]

6. orm

對象關係映射(Object Relational Mapping,簡稱ORM)是經過使用描述對象和數據庫之間映射的元數據,將面嚮對象語言程序中的對象自動持久化到關係數據庫中。本質上就是將數據從一種形式轉換到另一種形式。
	
	對應關係
	 類  -- 表
	對象 -- 數據行
	屬性 -- 字段
* orm能夠操做表,操做數據行

6.1. 配置數據庫

  • **1. CMD命令行建立數據庫 : ** create database Day54

  • 2. settings.py的配置

    # settings.py下 :
    DATABASES = {
        'default': {
            'ENGINE' : 'django.db.backends.mysql',	# 數據庫類型
            'NAME' : 'Day54',	# 數據庫名
            'HOST' : '127.0.0.1',	 # IP地址
            'PORT' : 3306,	# 數據庫的端口
            'USER' : 'root'	# 數據庫用戶名
            'PASSWORD' : '2108'	# 密碼
        }
    }
  • 3. 使用pymysql模塊鏈接mysql數據庫 (__init__.py)

    在項目同名的文件夾下的__init__.py中 :  下面這兩行代碼也能夠不在__init__.py中,只要能運行就能夠
      # 導入pymysql模塊
      import pymysql	
      # 用pymysql模塊替換掉mysqldb模塊  由於默認使用的是mysldb模塊,此模塊僅支持python2,
      pymysql.install_as_MySQLdb()
  • **4. 寫pymysql模塊與數據庫的對應關係 **

    在app下的models.py中寫表結構 :
    from django.db import models
    class User(models.Model):   # 建立類,繼承Model類的功能
        username = models.CharField(max_length=32) # 數據庫中表的字段 類型爲varchar(32)
        password = models.CharField(max_length=32) # 數據庫中表的字段 類型爲varchar(32)
  • 5. 執行創數據庫遷移的命令

    pycharm的Teminal命令窗口下 :
    python manage.py  makemigrations  # 記錄下models.py的變動記錄並更新到 migrations 文件夾下的	             							001_inittal.py文件中
    python manage.py migrate   # 把變動記錄同步到數據庫中  這樣上面的數據庫表結構就寫入數據庫了
  • 6. 利用pycharm查看數據庫

    • **最新版的pycharm在鏈接中遇到因爲時區貳沒法鏈接數據庫的問題的解決辦法 😗*

      在鏈接數據庫窗口: 
      	在數據庫路徑後加 ?serverTimezone=GMT  便可
    • **注意 😗*

      在pycharm中修改數據庫後須要提交,修改纔會生效

  • 7. 利用數據庫進行用戶名密碼校驗

    from django.shortcuts import render,redirect
    
    from app01 import models # 導入models.py中的User等類
    
    def login(requset):
        if requset.method == 'GET':
            # 返回登陸頁面
            return render(requset,'login.html')
        elif requset.method == 'POST':
            # 獲取提交的數據 (用戶名和密碼)
            user = requset.POST.get('username')
            pwd = requset.POST.get('password')
            # 對用戶名和密碼進行校驗
            ret = models.User.objects.filter(username=user,password=pwd)
            #  filter - 過濾篩選  查不到爲空(False)對象列表
           # ret = models.User.objects.get(username=user,password=pwd) 
           #  get - 找不到會報錯,找到多個也會報錯
            if ret:
                # 校驗成功,跳轉到設置頁面(重定向)
                return redirect('http://donyz.s567.tw/')
            else:
                # 校驗失敗,從新登陸
                return render(requset,'login.html')

7. 圖書管理系統

出版社 | 圖書 | 做者

7.1. 出版社的管理

  • 展現
  • 新增
  • 刪除
  • 編輯

具體流程

7.11. 配置數據庫

  • **a. 命令行建立數據庫 😗*

    create database day55_bookmanager

  • **b. 項目配置數據庫 😗*

    settings.py

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'day55_bookmanager',
            'HOST': '127.0.0.1',
            "PORT": 3306,
            "USER": 'root',
            'PASSWORD': '2108'
        }
    }
  • **c. 用pymysql替換MYSQLdb模塊 😗*

    **項目下 __init.py文件 😗*

    import pymysql
    pymysql.install_as_MySQLdb()
  • **d. app下建立表結構 😗*

    **modes.py文件下 😗*

    from django.db import models
    
    class Publisher(models.Model):
        #  AutoField -自增加類型,映射到數據庫中是11位的整數,使用此字段時,必須傳遞primary_key=True,
        # 不然在生成遷移腳本文件時,就會報錯
        pid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        def __str__(self): # 幫助打印對象中具體的屬性值
            return "{}{}".format(self.pid,self.name)
  • **e. 執行創數據庫遷移的命令 😗*

    pycharm的Teminal命令窗口下 :
    1. python manage.py  makemigrations  
    # 記錄下models.py的變動記錄並更新到 migrations 文件夾下001_inittal.py文件中
    2. python manage.py migrate   
    # 把變動記錄同步到數據庫中  這樣上面的數據庫表結構就寫入數據庫了
  • 給表添加一些數據

7.1.2 展現出版社頁面

  • A.urls.py 寫對應關係:

    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publisher_list/', views.publisher_list),
    ]
  • **B.appviews.py寫業務邏輯 😗*

    from django.shortcuts import render
    from app01 import models
    def publisher_list(request):
        # 從數據庫中查詢全部的出版社
        all_pubilshers = models.Publisher.objects.all() # 獲取數據庫所有數據,返回的是一個對象列表
        # 返回一個頁面
        return render(request,'publisher_list.html',{'xxx':all_pubilshers})
        # xxx爲自定義的key,在前端頁面用固定格式 :{{xxx}} 能夠引用xxxkey的值all_pubilshers
  • C.publisher_list.html圖書管理網頁

    <table border="1">
        <thead>  <!-- 表頭 -->
        <tr>    <!-- 一行 -->
            <th>序號</th>
            <th>ID</th>
            <th>出版社名稱</th>
        </tr>
        </thead>
        <tbody>  <!-- 主體內容 -->
            {% for publisher in xxx%} <!-- 循環語句  xxx爲後端數據庫的全部數據-->
                <tr>
                <td>{{ forloop.counter }}</td> <!--forloop.counter 爲for循環次數計數 對應序號-->
                <td>{{ publisher.pid }}</td> <!--pid等同於pk (primarykey)-->
                <td>{{ publisher.name }}</td>
                </tr>
            {% endfor %} <!-- 閉合語句 -->
        </tbody>
    </table>

7.13. 新增數據 ( 新增出版社)

  • **數據庫修改惟一 😗*

    from django.db import models
    
    class Publisher(models.Model):
        #  AutoField -自增加類型,映射到數據庫中是11位的整數,使用此字段時,必須傳遞primary_key=True,
        # 不然在生成遷移腳本文件時,就會報錯
        pid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32,unique=True) # 惟一
        def __str__(self): #幫助打印對象中具體的屬性值
            return "{}{}".format(self.pid,self.name)
    
    執行創數據庫遷移的命令 :
    pycharm的Teminal命令窗口下 :
    1. python manage.py  makemigrations  
    # 記錄下models.py的變動記錄並更新到 migrations 文件夾下001_inittal.py文件中
    2. python manage.py migrate   
    # 把變動記錄同步到數據庫中  這樣上面的數據庫表結構就寫入數據庫了
  • 提交新增圖書頁面

    <body>
    <form action="" method="post">
        <p>
            請輸入新增出版社名稱 : <input type="text" name="pub_name" value="{{ pub_name }}">
            <span style="color: red">{{ error }}</span>
        </p>
        <button>提交</button>
    </form>
    </body>
  • 展現頁面

    <body>
    <table border="1">
        <thead>  <!-- 表頭 -->
        <tr>    <!-- 一行 -->
            <th>序號</th>
            <th>ID</th>
            <th>出版社名稱</th>
        </tr>
        </thead>
        <tbody>  <!-- 主體內容 -->
            {% for publisher in xxx%} <!-- 循環語句  xxx爲後端數據庫的全部數據-->
                <tr>
                <td>{{ forloop.counter }}</td> <!--forloop.counter 爲for循環次數計數 對應序號-->
                <td>{{ publisher.pid }}</td> <!--pid等同於pk (primarykey)-->
                <td>{{ publisher.name }}</td>
                </tr>
            {% endfor %} <!-- 閉合語句 -->
        </tbody>
    </table>
    <a href="/publisher_add/"><button>添加</button></a>	<!--<a href="/" ></a> 表示連接到網站根目錄.
    <a href="/porducts/" ></a> 表示連接到根目錄下的products目錄.-->
    </body>
  • appviews.py寫業務邏輯

    def publisher_add(requset):
        pub_name,error = '', ''
        if requset.method == "POST":
            # 獲取用戶提交的信息 (出版社名字)
            pub_name = requset.POST.get('pub_name')
            if not pub_name:
                # 輸入爲空
                error = "輸入不能爲空"
            elif models.Publisher.objects.filter(name=pub_name):
                # 數據已經存在
                error = "數據已經存在"
            else:
                # 用戶輸入正確,數據寫入數據庫
                # 方式一 :
                models.Publisher.objects.create(name=pub_name)
                # 方式二 :
                # obj = models.Publisher(name = pub_name) # 在內存中實例化對象
                # obj.save()
                # 跳轉到展現頁面
                return redirect('/publisher_list/')
        return render(requset,'publisher_add.html',{'pub_name':pub_name,'error':error})
  • urls.py 寫對應關係

    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publisher_list/', views.publisher_list),
        url(r'^publisher_add/', views.publisher_add),
    ]

7.14. 刪除數據 (刪除出版社)

  • 在以前基礎上須要修改的

    • 展現界面添加操做相關按鈕

      <body>
      <table border="1">
          <thead>  <!-- 表頭 -->
          <tr>    <!-- 一行 -->
              <th>序號</th>
              <th>ID</th>
              <th>出版社名稱</th>
              <th>操做</th>
          </tr>
          </thead>
          <tbody>  <!-- 主體內容 -->
              {% for publisher in xxx%} <!-- 循環語句  xxx爲後端數據庫的全部數據-->
                  <tr>
                  <td>{{ forloop.counter }}</td> <!--forloop.counter 爲for循環次數計數 對應序號-->
                  <td>{{ publisher.pid }}</td> <!--pid等同於pk (primarykey)-->
                  <td>{{ publisher.name }}</td>
                  <td><a href="/publisher_del/?pk={{ publisher.pk }}"><button>刪除</button></a></td>
                  </tr>
              {% endfor %} <!-- 閉合語句 -->
          </tbody>
      </table>
      <a href="/publisher_add/"><button>添加</button></a>
      </body>
  • urls.py寫對應關係

    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publisher_list/', views.publisher_list),
        url(r'^publisher_add/', views.publisher_add),
        url(r'^publisher_del/', views.publisher_del),
    ]
  • views.py增長定義函數,寫業務邏輯代碼

    # 刪除數據
    def publisher_del(request):
        # 利用get請求拿到要刪除的數據id
        pk = request.GET.get('pk')
        # 驗證要刪除的數據是否存在
        query = models.Publisher.objects.filter(pid=pk)
        if not query :
            # 數據不存在返回一個字符串
            return HttpResponse('要刪除的數據不存在')
        # 經過queryset刪除查到的全部數據
        # 刪除方式一 :
        query.delete()
        # # 刪除方式二 刪除一個對象:
        # query[0].delete()
        # 跳轉到展現頁面
        return redirect('/publisher_list/')

7.15. 編輯數據 (編輯出版社)

  • 編輯頁面

    <body>
    <form action="" method="post">
        <p>
            請輸入編輯出版社的新名稱 : <input type="text" name="pub_name" value="{{ obj.name }}">
            <span style="color: red">{{ error }}</span>
        </p>
        <button>提交</button>
    </form>
    </body>
  • 展現界面添加操做相關按鈕

    <body>
    <table border="1">
        <thead>  <!-- 表頭 -->
        <tr>    <!-- 一行 -->
            <th>序號</th>
            <th>ID</th>
            <th>出版社名稱</th>
            <th>操做</th>
        </tr>
        </thead>
        <tbody>  <!-- 主體內容 -->
            {% for publisher in xxx%} <!-- 循環語句  xxx爲後端數據庫的全部數據-->
                <tr>
                <td>{{ forloop.counter }}</td> <!--forloop.counter 爲for循環次數計數 對應序號-->
                <td>{{ publisher.pid }}</td> <!--pid等同於pk (primarykey)-->
                <td>{{ publisher.name }}</td>
                <td><a href="/publisher_del/?pk={{ publisher.pk }}"><button>刪除</button></a>
                    <a href="/publisher_edit/?pk={{ publisher.pk }}"><button>編輯</button></a>
                </td>
                </tr>
            {% endfor %} <!-- 閉合語句 -->
        </tbody>
    </table>
    <a href="/publisher_add/"><button>添加</button></a>
    </body>
  • urls.py寫對應關係

    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publisher_list/', views.publisher_list),
        url(r'^publisher_add/', views.publisher_add),
        url(r'^publisher_del/', views.publisher_del),
        url(r'^publisher_edit/', views.publisher_edit),
    ]
  • views.py增長定義函數,寫業務邏輯代碼

    # 編輯數據
    def publisher_edit(request):
        error = ''
        # 獲取要查詢的ID
        pk = request.GET.get('pk')
        # 查詢要編輯的對象
        obj = models.Publisher.objects.filter(pk =pk).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})

8. 外鍵

8.1. get 和 post的區別

get :

發get請求的方式:
1. form表單     不指定method
2. 在地址欄中直接輸入地址 回車
3. a標題 
?k1=v1&k2=v2      request.GET     request.GET.get('k1')

post :

form表單     method='post'	
request.POST     request.POST.get('k1')

8.2. orm - 表操做

面向對象和關係型數據庫的一種映射

對應關係:
​	類     ——》    表
​	對象  ——》    記錄 (數據行)
​	屬性  ——》    字段

from app import  models

查詢:

​	models.Publisher.objects.get(name='xxxxx')       # 查詢一個對象  有且惟一   差很少或者多個就報錯
​	models.Publisher.objects.filter(name='xxxxx')      # 查詢知足條件全部對象     對象列表  queryset  

​	models.Publisher.objects.all()   # 查詢全部的數據  對象列表  queryset  

新增:
​	models.Publisher.objects.create(name='xxxxx')   # 返回值 就是新建的對象
​	obj = models.Publisher(name='xxxxx')     obj.save()

刪除:
​	models.Publisher.objects.filter(pk=1) .delete() 
​	obj = models.Publisher.objects.filter(pk=1) .first()   obj.delete()

修改:
​	obj = models.Publisher.objects.filter(pk=1) .first()
​	obj.name =  'xxxxx'
​	obj.save()

8.3 外鍵 的設置

一對多的對應關係 - 外鍵建立在多的一方

class Book(models.Model):
    title = models.CharField(max_length=32)
    pid = models.ForeignKey('Publisher', on_delete=models.CASCADE)
    # 外鍵  Publisher爲對應關聯的表
    #  on_delete  django2.0中 必填

on_delete參數的各個值的含義:

1. on_delete=None,               # 刪除關聯表中的數據時,當前表與其關聯的field的行爲
2. on_delete=models.CASCADE,     # 刪除關聯數據,與之關聯也刪除 - 級聯刪除
3. on_delete=models.DO_NOTHING,  # 刪除關聯數據,什麼也不作
4. on_delete=models.PROTECT,     # 刪除關聯數據,引起錯誤ProtectedError

models.ForeignKey('關聯表', on_delete=models.SET_NULL, blank=True, null=True)

5. on_delete=models.SET_NULL,
# 刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空,一對一同理)

models.ForeignKey('關聯表', on_delete=models.SET_DEFAULT, default='默認值')

6. on_delete=models.SET_DEFAULT,
# 刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值,一對一同理)

7. on_delete=models.SET,         # 刪除關聯數據,
 a. 與之關聯的值設置爲指定值,設置:models.SET(值)
 b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)

查詢:

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))  # book.pub爲所關聯的對象
    print(book.pub_id,type(book.pub_id))  # 所關聯的對象的pk

**新增 😗*

models.Book.objects.create(title=title,pub=models.Publisher.objects.get(pk=pub_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()

9. 多對多表結構設計

表結構的設計

class Book(models.Model):
    title = models.CharField(max_length=32)
    pid = models.ForeignKey('Publisher',on_delete=models.CASCADE)

class Author(models.Model):
    name = models.CharField(max_length=32)
    book = models.ManyToManyField('Book') # 描述多對的關係 不生成此字段,而是生成Author-Book的關係表

查表

all_authors = models.Author.objects.all().order_by('id')
for author in all_authors:
    print(author.name)
    print(author.pk)
    print(author.books)  # 關係管理對象
    print(author.books.all())  # 所關聯的全部對象
models.py :
class Book(models.Model):
    title = models.CharField(max_length=32)
    pid = models.ForeignKey('Publisher',on_delete=models.CASCADE)
    def __repr__(self):
        return self.title
    __str__ = __repr__

class Author(models.Model):
    name = models.CharField(max_length=32)
    book = models.ManyToManyField('Book') # 描述多對的關係 不生成此字段,而是生成Author-Book的關係表
author.html頁面 :
    <tr>
    <td>{{ forloop.counter }}</td>
    <td>{{ author.pk }}</td>
    <td>{{ author.name }}</td>
    <td>{% for book in author.book.all %}
        {{ book }}
    {% endfor %}</td>
views.py 邏輯
def author_list(request):
    all_author = models.Author.objects.all()
    return render(request, 'author_list.html', {'all_author': all_author})

新增

books = request.POST.getlist('books')   # 獲取多個元素

# 新建做者
author_obj = models.Author.objects.create(name=name)
# 給做者和書籍綁定關係
author_obj.books.set(books) #

建立多對多的表的方法

  • 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):
        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)
        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()

設計表結構

nodels

<form class="form-inline" method="post">
    <div class="form-group">
        <input type="text" class="form-control" id="exampleInputEmail3" name="author_name"
                placeholder="{{ author_obj.name }}">
        <span style="color: crimson">{{ error }}</span>
        著做 :<select name="book_id" multiple>
        {% for book in all_books %}
            {% if book in author_obj.book.all %}
             <option selected value="{{ book.pk }}">{{ book.title }}</option>
                {% else %}
                  <option value="{{ book.pk }}">{{ book.title }}</option>
            {% endif %}
        {% endfor %}
    </select>
    </div>
    <button type="submit" class="btn btn-default">提交</button>
</form>

展現

views

def author_list(request):
    all_author = models.Author.objects.all()
    return render(request, 'author_list.html', {'all_author': all_author})

html

<table class="table table-striped table table-hover">
    <thead>
    <tr>
        <th>序號</th>
        <th>ID</th>
        <th>做者</th>
        <th>著做</th>
        <th>操做</th>
    </tr>
    </thead>
    <tbody>
    {% for author in all_author %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ author.pk }}</td>
            <td>{{ author.name }}</td>
            <td>{% for book in author.book.all %}
                《{{ book }}》
            {% endfor %}</td>
            <td><a href="/author_del/?pk={{ author.pk }}" class="btn btn-danger">刪除</a>
                <a href="/author_edit/?pk={{ author.pk}}" class="btn btn-warning">編輯</a></td>
        </tr>
    {% endfor %}
    </tbody>
</table>

刪除

views

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

新增

views

def author_add(request):
    error = ''
    if request.method == "POST":
        author_name = request.POST.get('author_name')
        book = request.POST.getlist('list_book')
        if not author_name or not book:
            error = '輸入或選擇不能爲空!'
        elif models.Author.objects.filter(name=author_name):
            error = '做者已存在!'
        else:
            author_obj = models.Author.objects.create(name=author_name)
            author_obj.book.set(book)
            return redirect('/author_list/')
    all_books = models.Book.objects.all()
    return render(request, 'author_add.html', {'all_books': all_books, 'error': error})

html

<form class="form-inline" method="post">
    <div class="form-group">
        <input type="text" class="form-control" id="exampleInputEmail3" name="author_name"
               placeholder="請填寫做者">
        <span style="color: crimson">{{ error }}</span>
            著做:
            <select name="list_book"  multiple>
                {% for book in all_books %}
                    <option value="{{ book.pk }}">{{ book.title }}</option>
                {% endfor %}
            </select>
    </div>
    <button type="submit" class="btn btn-default">提交</button>
</form>

編輯

views

def author_edit(request):
    error = ''
    pk = request.GET.get('pk')
    author_obj = models.Author.objects.filter(pk=pk).first()
    if not models.Author.objects.filter(pk=pk):
        return HttpResponse('數據不合法!')
    if request.method == "POST":
        author_name = request.POST.get('author_name')
        book_id = request.POST.getlist('book_id')
        if not author_name or not book_id:
            error = '輸入或選擇不能爲空'
        elif models.Author.objects.filter(name=author_name):
            error = '做者已存在!'
        else:
            author_obj.name = author_name
            author_obj.save()
            author_obj.book.set(book_id)
            return redirect('/author_list/')
    all_books = models.Book.objects.all()
    return render(request, 'author_edit.html', {'all_books': all_books, 'error': error, 'author_obj': author_obj})

html

<form class="form-inline" method="post">
    <div class="form-group">
        <input type="text" class="form-control" id="exampleInputEmail3" name="author_name"
                placeholder="{{ author_obj.name }}">
        <span style="color: crimson">{{ error }}</span>
        著做 :<select name="book_id" multiple>
        {% for book in all_books %}
            {% if book in author_obj.book.all %}
             <option selected value="{{ book.pk }}">{{ book.title }}</option>
                {% else %}
                  <option value="{{ book.pk }}">{{ book.title }}</option>
            {% endif %}
        {% endfor %}
    </select>
    </div>
    <button type="submit" class="btn btn-default">提交</button>
</form>

10. MVC和MTV框架

MVC

MVC全名是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,一種軟件設計典範,用一種業務邏輯、數據、界面顯示分離的方法組織代碼,將業務邏輯彙集到一個部件裏面,在改進和個性化定製界面及用戶交互的同時,不須要從新編寫業務邏輯。具備耦合性低、重用性高、生命週期成本低等優勢。

結構

1. Model (模型): 
    核心的"數據層"(Model),也就是程序須要操做的數據或信息。
2. View (視圖): 
    直接面向最終用戶的"視圖層"(View)。它是提供給用戶的操做界面,是程序的外殼。
3. Controller (控制層) : 
    是"控制層"(Controller),它負責根據用戶從"視圖層"輸入的指令,選取"數據層"中的數據,而後對其進行相應的操做,產生最終結果。

MTV

MTV 是Django定義的一種開發規範

結構

Model(模型):負責業務對象與數據庫的對象(ORM)
Template(模版):負責如何把頁面展現給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template

11. Django模板系統

經常使用語法

{{  }}和 {% %}
{{ }}表示變量,在模板渲染的時候替換成值,{% %}表示邏輯相關的操做。
{{ 變量名 }}
變量名由字母數字和下劃線組成。
點(.)在模板語言中有特殊的含義,用來獲取對象的相應屬性值。
views.py中的數據:
    context = {
        "filter_list": ['西遊記', '水滸傳', '紅樓夢', '三國演義'],
        "filter_dict": {
            'name': "小豬佩奇",
            'age': 3,
            'hobby': "睡覺"
        }
    }
前端頁面操做 :
# 取filter_list中的第一個參數
{{ filter_list.0 }} # 西遊記

# 取字典中key的值 
{{ filter_dict.name }} # 小豬佩奇
{# 取對象的name屬性 #}
{{ person_list.name }}
{# .操做只能調用不帶參數的方法 #}
{{ person_list.dream }}
注:當模板系統遇到一個(.)時,會按照以下的順序去查詢:
	1. 在字典中查詢
	2. 屬性或者方法
	3. 數字索引

filters - 過濾器

filters - 用來修飾變量的顯示結果

語法: {{ value|filter_name:參數 }}
':'左右沒有空格沒有空格沒有空格

default  

{{ value|default:"nothing"}}

若是value值沒傳的話就顯示nothing
注:TEMPLATES的OPTIONS能夠增長一個選項:string_if_invalid:'找不到',能夠替代default的的做用

filesizeformat

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

{{ value|filesizeformat }}

add

給前端變量加參數

{{ value|add:"2" }}

{{ first|add:second }} 若是first、second都是列表

如first=[1,2,3],second = [4,5,6], 那麼結果是兩個列表的合併 :[1,2,3,4,5,6]

lower/upper - 大小寫

{{ value|lower }} {{ value|upper}}

title -標題

{{ value|title }}

length

{{ value|length }} - 返回的是value的長度

slice - 切片

{{value|slice:"2:-1"}}

first/last -取 第一個/最後一個

{{ value|first }} {{ value|last }}

join - 拼接字符串

使用字符串拼接列表。同python的str.join(list)。 {{ value|join:" // " }}

truncatechars - 截斷

truncatewords - 按照單詞截斷

若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。

參數:截斷的字符數 {{ value|truncatechars:9}}

date -日期

日期格式化 {{ value|date:"Y-m-d H:i:s"}}

views.py中
import datetime
context{
	'now':datetime.datetime.now(),
}
{{ now|date:"Y-m-d H:i:s"}}
settings的配置:
USE_L10N = False
DATETIME_FORMAT = 'Y-m-d H:i:s'
DATE_FORMAT = 'Y-m-d'
TIME_FORMAT = 'H:i:s'

safe

**在先後端傳輸變量數據的時候,前端引用的後端的多是一串前端代碼,在默認的狀況下,爲了安全,前端會轉義成字符串, 若是想要運行這串引用的代碼,就須要加safe {{ value|safe}}**

在py後臺中先解除不安全

from django.utils.safestring import mark_safe	# 導入模塊

'a':mark_safe('<a href="http://www.baidu.com">跳轉</a>')	# 定義數據的時候用mark_safe(數據)

自定義過濾器

步驟 :

1. 在app下建立名字必須爲 templatetags 的python包
2. 在templatetags包內建立python文件 :
    from django import template # 導入模板
    register = template.Library() # register 爲固定寫法,不能變
    # 寫過濾器
    @register.filter  # 必須加裝飾器
    def 過濾器名(value,arg=None): # 至多能夠接收兩個參數,一個是value變量,一個是過濾器的參數(:後面的參數)
        return value.upper() # 變成大寫
    
 3. 前端頁面寫法 
	{% load python文件 %} # 加載過濾器
    {{ value|過濾器名 }}

12. Tags - 標籤

for -循環

<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% endfor %}
</ul>

for...empty

<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% empty %}
    <li>空的數據</li>
{% endfor %}
</ul>
<!--若for循環取不到值,則會執行empty中的內容-->

取餘數

{% num|divisibleby:2 %}  <!-- 對num取2的餘數-->

if,elif和lese

{% if age<18 %}
  未成年
{% elif age<30 %}
  青年人
{% else %}
  中年人
{% endif %}

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

且 if 不支持算數運算、不支持連續判斷

with

定義中間變量 , 給變量起別名

方式一 :
{% with 舊名字 as 新的名字 %}
這裏就能夠引用新的名字
{% endwith %}

方式二 :
{% with 新的名字=舊名字  %}
這裏就能夠引用新的名字
{% endwith %}

csrf_token

這個標籤用於跨站請求僞造保護。

在頁面的form表單裏面寫上 {% csrf_token %}


13. 模板和繼承

寫模板

下面的表格模擬html模板 ( 假設這個頁面叫 " 模板.html " )

固定頁面 固定頁面
固定頁面 '' 須要替換的頁面 ''

content 爲這個模塊的名稱
content{% block content %}

{% endblock %}

繼承使用模板

{ % extends '模板.html'%}	<!-- 導入模板-->

{ % block 模塊名% }	<!-- 這裏的模塊麼要和模板的模塊名一致-->

這裏寫本身的內容

{ % endblock% }

若是子頁面要單獨用一個樣式css 或js,

那麼就能夠單獨的使用block塊引用,避免其餘子頁面的時候也加載了沒必要要的樣式


小組件

在主界面須要插入小組件的地方如 導航欄等 寫入代碼{%include '組件名.html%}

組件名.html 中,不須要head,body等,能夠直接寫代碼


14. 靜態文件別名

動態獲取static別名

**方式一 😗*

{% load stati %}	加載動態static別名
<!--這樣不管配置中的static別名設置成什麼,均可以用static動態獲取到 -->
<!--引用文件直接在{%staticc 'css/xxcss' %} -->
例 :
<link rel="stylesheet" href="{% static 'css/dashboard.css' %}">

**方式二 😗*

{% load stati %}
<!--獲取動態文件前綴 { % get_static_prefix %}  - 找到動態文件別名-->
例 :
<link rel="stylesheet" href="{% get_static_prefix %}css/cssyangs.css">

15. 自定義simpletag

在templatetags中的py文件中
from django import template
register = template.Library() 
        
@register.simple_tag
def join_str(*args, **kwargs):
    return '_'join(args) + "*".join(kwargs.values())

前端頁面引用 :
{% load my_tags %}  # my_tags 爲 emplatetags 的py文件
{% join_str 'v1' 'v2' k3='k3' k4='v4' %}  # 結果 : v1_v2k3*k4

16. 自定義inclusion_tag

分頁

  1. 在app中建立名字爲templatetags的python包

  2. 在templatetags中出建立python文件my_tags.py

  3. 在建立的python中寫自定義函數

    from django import template
    register = template.Library() 
    
    @register.inclusion_tag('html模板.html')
    def page(num):
        return {'num':range(1,num+1)}	# 返回的必須是個字典 會把num傳到html模板.html
  4. 新建HTML,寫分頁模板

    <nav aria-label="Page navigation">
      <ul class="pagination">
        <li>
          <a href="#" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>
        {% for i in num %}
          <li><a href="#">{{i}}</a></li>
          {% endfor %}
        <li>
          <a href="#" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
      </ul>
    </nav>
  5. 在須要分頁的頁面導入分頁小組件

    {% load my_tags %} # 加載自定義模塊my_tags
    {% page 5 %}	# 會把5這個參數傳回到函數中,表示的是分5頁
相關文章
相關標籤/搜索