Django-手擼簡易web框架-實現動態網頁-wsgiref初識-jinja2初識-python主流web框架對比-00

[TOC]css

本身動手實現一個簡易版本的web框架

在瞭解python的三大web框架以前,咱們先本身動手實現一個。html

備註:前端

這部分重在掌握實現思路,代碼不是重點python

代碼中也有許多細節並未考慮,重在實現思路mysql

手擼一個web服務端

咱們通常是使用瀏覽器當作客戶端,而後基於HTTP協議本身寫服務端代碼做爲服務端jquery

先自行去回顧一下HTTP協議這一起的知識web

import socket
server = socket.socket()  # 基於socket通訊(TCP)
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
    conn, addr = server.accept()
    data = conn.recv(2048)  # 接收請求
    print(str(data, encoding='utf-8'))
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 依據HTTP協議,發送響應給客戶端(瀏覽器),這裏是響應首行 + 響應頭 + 空行
    # response = bytes('<h3>這是響應內容</h3>', encoding='GBK')
    response = '<h3>這是響應內容</h3>'.encode('GBK')  # 我電腦上是GBK編碼,因此使用GBK編碼將字符串轉成二進制
    conn.send(response)  #  繼續發送響應體
    conn.close()  # 斷開鏈接(無狀態、無鏈接)

# 瀏覽器發過來的數據以下
'''
GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs


GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://127.0.0.1:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs
'''

而後右鍵運行,在瀏覽器訪問 127.0.0.1:8080 便可看到響應數據sql

關於啓動服務器與頁面請求(在我處理的時候,頁面網絡請求會常常處於 pending狀態,不是很清楚緣由,通常這個狀況下,直接重啓一下服務器便可)數據庫

根據請求 url 作不一樣的響應處理

上面的代碼已經實現了基本請求響應,那如何根據不一樣的請求做出不一樣的響應呢?django

咱們輸入不一樣的url,看看服務器端會返回什麼

分析請求

瀏覽器訪問 http://127.0.0.1:8080/index
GET /index HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs
    

瀏覽器訪問 http://127.0.0.1:8080/home   
GET /home HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs

原來請求首行的 GET 後面跟的就是請求咱們想要信息(/index 首頁、/home 家)

這些信息也是咱們接收到的(data = conn.recv(2048) print(str(data, encoding='utf-8'))),那可不能夠取出來,根據值的不一樣做不一樣處理呢?

處理請求,獲取 url

data = '''GET /home HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs'''
print(data.split('\n')[0].split(' ')[1])  # ... ---> GET /home HTTP/1.1 --> ['GET', '/home', 'HTTP/1.1']  --> /home
# /home

依據上述切割規則,咱們來對不一樣的請求做出不一樣的響應

import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
    conn, addr = server.accept()
    data = conn.recv(2048).decode('utf-8')
    data = data.split('\n')[0].split(' ')[1]
    print(data)
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    if data == '/index':
        response = '<h3>這裏是 index...</h3>'.encode('GBK')
    elif data == '/home':
        response = '<h3>這裏是 home...</h3>'.encode('GBK')
    else:
        response = '<h3>404 NOT FOUND...\n找不到您要找的資源...</h3>'.encode('GBK')
    conn.send(response)
    conn.close()

# --- 瀏覽器請求 http://127.0.0.1:8080/index 的打印信息
# /index
# /favicon.ico
# --- 瀏覽器請求 http://127.0.0.1:8080/home 的打印信息
# /home
# /favicon.ico
# --- 瀏覽器請求 http://127.0.0.1:8080/de2332f 的打印信息
# /de2332f
# /favicon.ico

頁面成功顯示不一樣的信息

http://127.0.0.1:8080/index

http://127.0.0.1:8080/home

http://127.0.0.1:8080/de2332f

404頁面也應該算做設計網站的一部分,能夠給人不同的感受

基於wsgiref模塊實現服務端

前面處理 scoket 和 http 的那堆代碼一般是不變的,且與業務邏輯沒什麼關係,若是每一個項目都要寫一遍,那豈不是很麻煩?那封裝成模塊嘛~

不過這個操做已經有人幫咱們作了,而且封裝的更增強大,就是 wsgiref 模塊

用wsgiref 模塊的作的兩件事

  1. 在請求來的時候,自動解析 HTTP 數據,並打包成一個字典,便於對請求發過來的數據進行操做
  2. 發響應以前,自動幫忙把數據打包成符合 HTTP 協議的格式(響應數據格式,不須要再手動寫 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') 了),返回給服務端
from wsgiref.simple_server import make_server  # 導模塊


def run(env, response):
    """
    先無論這裏的 env 和 response 什麼個狀況

    env:是請求相關的數據,wsgiref幫咱們把請求包裝成了一個大字典,方便取值
    response:是響應相關的數據
    """
    response('200 OK', [])
    print(env)
    current_path = env.get('PATH_INFO')
    print(current_path)

    if current_path == '/index':
        return ['hello, there is index...'.encode('utf-8')]
    elif current_path == '/login':
        return ['hello, there is login...'.encode('utf-8')]
    else:
        return ['sorry... that pages you want is not found...'.encode('utf-8')]


if __name__ == '__main__':
    # 實時監測 127.0.0.1:8080 地址,一旦有客戶端鏈接,會自動加括號調用 run 方法
    server = make_server('127.0.0.1', 8080, run)
    server.serve_forever()  # 啓動服務器


# /index
# ---> env 的數據(手動刪減了一些),能夠看到其中有個 PATH_INFO 是咱們要的東西(還有瀏覽器版本啊,USER-AGENT啊,客戶端系統環境變量啊之類的信息)
'''{'ALLUSERSPROFILE': 'C:\\ProgramData', ...省略部分... , 'COMSPEC': 'C:\\Windows\\system32\\cmd.exe', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 60 Stepping 3, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '3c03', 'PYTHONIOENCODING': 'UTF-8',  'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SERVER_PORT': '8080', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/index', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8080', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs', mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), }'''

伏筆

拆分服務端代碼

服務端代碼、路由配置、視圖函數,照目前的寫法全都冗在一起,後期功能擴展時,這個文件會變得很長,不方便維護,因此選擇把他拆分開來

就是將服務端代碼拆分紅以下三部分:

  • server.py 放服務端代碼

  • urls.py 放路由與視圖函數對應關係

  • views.py 放視圖函數/類(處理業務邏輯)

views.py

def index(env):
    return 'index'


def login(env):
    return 'login'

urls.py

from views import *

urls = [
    ('/index', index),
    ('/login', login),
]

server.py

from wsgiref.simple_server import make_server  # 導模塊
from urls import urls  # 引入 urls.py 裏的 urls列表(命名的不是很規範)


def run(env, response):
    response('200 OK', [])
    current_path = env.get('PATH_INFO')

    func = None
    for url in urls:
        if current_path == url[0]:
            func = url[1]
            break

    if func:
        res = func(env)
    else:
        res = '404 Not Found.'
    return [res.encode('utf-8')]  # 注意這裏返回的是一個列表(可迭代對象才行),wsgiref 模塊規定的,可能還有其餘的用途吧


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)
    server.serve_forever()

支持新的請求地址(添加新頁面/新功能)

通過上面的拆分後,後續想要支持其餘 url,只須要在 urls.py 中添加一條對應關係,在 views.py 中把該函數實現,重啓服務器便可訪問

以支持 http://127.0.0.1:8080/new_url 訪問爲例

urls.py

from views import *

urls = [
    ('/index', index),
    ('/login', login),
    ('/new_url', new_url),
]

views.py

def index(env):
    return 'index'


def login(env):
    return 'login'


def new_url(env):
    # 這裏能夠寫一堆邏輯代碼
    return 'new_url'

重啓服務器,打開瀏覽器便可訪問 http://127.0.0.1:8080/new_url

擴展性高了不少,且邏輯更清晰了,更不容易弄錯(框架的好處提現,也是爲何脫離了框架不會寫的緣由,這塊代碼寫的太少,不經常使用到,沒了框架又寫不出來)

動態靜態網頁--拆分模板文件

前面寫了那麼多,都只是一直在返回純文本信息,而咱們通常請求頁面返回的都是瀏覽器渲染好的華麗的頁面,那要怎麼放回華麗的頁面呢?

頁面嘛,就是 HTML + CSS + JS 渲染出來的,因此咱們也能夠把 HTML文件當成數據放在響應體裏直接返回回去

新建一個功能的步驟仍是複習一下

  • 在 urls.py 裏面加一條路由與視圖函數的對應關係
  • 在 views.py 裏面加上那個視圖函數,並寫好內部邏輯代碼
  • 重啓服務器,瀏覽器打開頁面訪問

返回靜態頁面--案例

這裏我們就接着上面的 new_url 寫,用他來返回 一個網頁

新建一個 templates 文件夾,專門用來放 HTML 文件

templates/new_url.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>New URL</h1>
    <h5>Wellcome!</h5>
</body>
</html>

views.py

def index(env):
    return 'index'


def login(env):
    return 'login'


def new_url(env):
    # 讀取並把 new_url 文件返回給客戶端(瀏覽器)
    with open(r'templates/new_url.html', 'rb') as f:
		html_data = f.read()
    return html_data.decode('utf-8')  # 由於 run 函數那裏作了 encode, 而二進制數據沒有 encode這個方法,因此這裏先解碼一下,而後那邊再編碼一下

重啓服務器,使用瀏覽器訪問

上面提到了靜態頁面,那什麼是靜態頁面?什麼又是動態頁面呢?

  • **靜態網頁:**純html網頁,數據是寫死的,全部同url的請求拿到的數據都是同樣的

  • **動態網頁:**後端數據拼接,數據不是寫死的,是動態拼接的,好比:

    ​ 後端實時獲取當前時間「傳遞」(塞)給前端頁面展現

    ​ 後端從數據庫獲取數據「傳遞」給前端頁面展現

實現返回時間--插值思路(動態頁面)

要怎麼在 html 裏插入時間呢?

往 html 裏的插入?那替換好像也能夠達到效果啊?

html_data = f.read() ? 好像 html 被讀出出來了,並且仍是二進制的,二進制能夠 decode 變成字符串,字符串有 replace方法能夠替換字符串,那我隨便在網頁裏寫點內容,而後替換成時間?

先把基礎歩鄹作好

templates/get_time.html 編寫展現頁面

put_times_here 用來作佔位符,一下子給他替換成時間

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>北京時間:</h1>
    <h1>put_time_here</h1>
</body>
</html>

urls.py 路由與視圖函數對應關係

from views import *

urls = [
    ('/index', index),
    ('/login', login),
    ('/new_url', new_url),
    ('/get_time', get_time),
]

views.py 實現視圖函數

def index(env):
    return 'index'


def login(env):
    return 'login'


def new_url(env):
    # 讀取並把 new_url 文件返回給客戶端(瀏覽器)
    with open(r'templates/new_url.html', 'rb') as f:
		html_data = f.read()
    return html_data


def get_time(env):
    # 讀取並把 get_time 文件返回給客戶端(瀏覽器)
    with open(r'templates/get_time.html', 'rb') as f:
        html_data = f.read().decode('utf-8')
    import time
    html_data = html_data.replace('put_time_here', time.strftime("%Y-%m-%d %X"))
    return html_data

重啓服務器並打開瀏覽器訪問 http://127.0.0.1:8080/get_time

關鍵思路:至關於佔位符,字符串替換,後期把前端要替換的字符的格式統一規定下,方便閱讀與統一處理,這其實也就是目前的模版語法的雛形

咱們只須要把處理好的字符串(HTML格式的)返回給瀏覽器,待瀏覽器渲染便可有頁面效果

利用 jinja2 模塊實現動態頁面

jinja2模塊有着一套 模板語法,能夠幫我更方便地在 html 寫代碼(就想寫後臺代碼同樣),讓前端也可以使用後端的一些語法操做後端傳入的數據

安裝 jinja2

jinja2 並非 python 解釋器自帶的,因此須要咱們本身安裝

​ 因爲 flask 框架是依賴於 jinja2 的,所下載 flask 框架也會自帶把 jinja2 模塊裝上

命令行執行,pip3 install jinja2圖形化操做安裝(參考 Django 的安裝方法)

初步使用

這裏只是知道有模板語法這麼一個東西可讓咱們很方便的往 html 寫一些變量同樣的東西,並不會講 jinja2 的語法,後續會有的

案例--展現字典信息

urls.py

from views import *

urls = [
    ('/index', index),
    ('/login', login),
    ('/new_url', new_url),
    ('/get_time', get_time),
    ('/show_dic', show_dic),
]

views.py

def index(env):
    return 'index'


def login(env):
    return 'login'


def new_url(env):
    # 讀取並把 new_url 文件返回給客戶端(瀏覽器)
    with open(r'templates/new_url.html', 'rb') as f:
		html_data = f.read()
    return html_data


def get_time(env):
    # 讀取並把 get_time 文件返回給客戶端(瀏覽器)
    with open(r'templates/get_time.html', 'rb') as f:
        html_data = f.read().decode('utf-8')
    import time
    html_data = html_data.replace('put_time_here', time.strftime("%Y-%m-%d %X"))
    return html_data


def show_dic(env):
    user = {
        "username": "jason",
        "age": 18,
    }
    with open(r'templates/show_dic.html', 'rb') as f:
        html_data = f.read()

    # 使用 jinja2 的模板語法來將數據渲染到頁面上(替換佔位符)
    from jinja2 import Template
    tmp = Template(html_data)
    res = tmp.render(dic=user)  # 將字典 user 傳遞給前端頁面,前端頁面經過變量名 dic 就可以獲取到該字典
    return res

templates/show_dic.html 寫頁面

jinja2 給字典擴展了點語法支持({{ dic.username }}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Nice to meet you~ i'm {{ dic.username }} , and i'm {{ dic.age }} years old.</h1>
    <p>username: {{ dic['username']}}</p>
    <p>age: {{ dic.get('age')}}</p>
</body>
</html>

重啓服務器並打開瀏覽器訪問 http://127.0.0.1:8080/show_dic

爲何說動態?

若是你改變了字典裏的值,那麼請求這個頁面,顯示的數據也會跟着改變(注意這個字典通常都是其餘地方獲取過來的)

模板語法(貼近python語法): 前端也可以使用後端的一些語法操做後端傳入的數據
	{{data.password}}  # jinja2 多給字典作了 點語法支持
    ... 其餘的語法,寫法
	
    for 循環
    {%for user_dict in user_list%}
    	<tr>
        	<td>{{user_dict.id}}</td>
        	<td>{{user_dict.name}}</td>
        	<td>{{user_dict.password}}</td>
        </tr>
    {%endfor%}

進階案例--渲染數據庫數據到頁面

思路

pymsql 從數據庫取數據(指定成 列表套字典 的格式(DictCursor))
後臺 python 代碼處理數據
交由 jinja2 模塊語法渲染到 html 頁面上

數據條數不定怎麼辦?
    有多少條記錄就顯示多少條唄...循環?
    表格格式先寫好,而後循環渲染數據到標籤上(特定語法表示循環)

數據準備

建立數據庫 django_test_db,而後執行以下 SQL 命令

/*
 Navicat MySQL Data Transfer

 Source Server         : localhost-E
 Source Server Type    : MySQL
 Source Server Version : 50645
 Source Host           : localhost:3306
 Source Schema         : django_test_db

 Target Server Type    : MySQL
 Target Server Version : 50645
 File Encoding         : 65001

 Date: 15/09/2019 00:41:09
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user_info
-- ----------------------------
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of user_info
-- ----------------------------
INSERT INTO `user_info` VALUES (1, 'jason', '123');
INSERT INTO `user_info` VALUES (2, 'tank', '123');
INSERT INTO `user_info` VALUES (3, 'jerry', '123');
INSERT INTO `user_info` VALUES (4, 'egon', '456');

SET FOREIGN_KEY_CHECKS = 1;

配路由與視圖函數

urls.py

from views import *

urls = [
    ('/index', index),
    ('/login', login),
    ('/new_url', new_url),
    ('/get_time', get_time),
    ('/show_dic', show_dic),
    ('/get_users', get_users),
]

views.py

def index(env):
    return 'index'


def login(env):
    return 'login'


def new_url(env):
    # 讀取並把 new_url 文件返回給客戶端(瀏覽器)
    with open(r'templates/new_url.html', 'rb') as f:
		html_data = f.read()
    return html_data


def get_time(env):
    # 讀取並把 get_time 文件返回給客戶端(瀏覽器)
    with open(r'templates/get_time.html', 'rb') as f:
        html_data = f.read().decode('utf-8')
    import time
    html_data = html_data.replace('put_time_here', time.strftime("%Y-%m-%d %X"))
    return html_data


def show_dic(env):
    user = {
        "username": "jason",
        "age": 18,
    }
    with open(r'templates/show_dic.html', 'rb') as f:
        html_data = f.read()

    # 使用 jinja2 的模板語法來將數據渲染到頁面上(替換佔位符)
    from jinja2 import Template
    tmp = Template(html_data)
    res = tmp.render(dic=user)  # 將字典 user 傳遞給前端頁面,前端頁面經過變量名 dic 就可以獲取到該字典
    return res


# 先寫個空函數在這裏佔位置,去把 pymysql 查數據的寫了再過來完善
def get_users(env):
    # 從數據庫取到數據
    import op_mysql
    user_list = op_mysql.get_users()

    with open(r'templates/get_users.html', 'r', encoding='utf-8') as f:
        html_data = f.read()

    from jinja2 import Template  # 其實這個引入應該放在頁面最上方去的,但爲了漸進式演示代碼推動過程,就放在這裏了
    tmp = Template(html_data)
    res = tmp.render(user_list=user_list)
    return res

**op_mysql.py **若是你的配置不同要本身改過來

import pymysql


def get_cursor():
    server = pymysql.connect(
        # 根據本身電腦上 mysql 的狀況配置這一塊的內容
        host='127.0.0.1',
        port=3306,
        user='root',
        password='000000',
        charset='utf8',  # 千萬注意這裏是 utf8 !
        database='django_test_db',
        autocommit=True
    )
    cursor = server.cursor(pymysql.cursors.DictCursor)
    return cursor


def get_users():
    cursor = get_cursor()  # 鏈接數據庫

    sql = "select * from user_info"  # 把用戶的全部信息查出來(通常不會把密碼放回給前端的,這裏只是爲了作演示)
    affect_rows = cursor.execute(sql)
    user_list = cursor.fetchall()
    return user_list

templates/get_users.html 用戶信息展現頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--  引入jquery bootstrap 文件的 CDN  -->
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
    <div class="container">
        <div class="row">

            <div class="col-md-8 col-md-offset-2">
                <h2 class="text-center">用戶數據展現</h2>
                <table class="table table-hover table-bordered table-striped">
                    <thead>
                    <tr>
                        <th>id</th>
                        <th>username</th>
                        <th>password</th>
                    </tr>
                    </thead>
                    <tbody>
                    <!-- jinja2 的模版語法(for循環) -->
                    {%for user_dict in user_list%}
                    <tr>
                        <td>{{user_dict.id}}</td>
                        <td>{{user_dict.username}}</td>
                        <td>{{user_dict.password}}</td>
                    </tr>
                    {%endfor%}
                    </tbody>
                </table>
            </div>

        </div>
    </div>
</body>
</html>

用瀏覽器訪問 http://127.0.0.1:8080/get_users,重啓服務器,在切回瀏覽器便可看到頁面效果

推導流程與小總結

1.純手擼web框架
    1.手動書寫socket代碼
    2.手動處理http數據
    
2.基於wsgiref模塊幫助咱們處理scoket以及http數據(頂掉上面的歩鄹)
	wsgiref模塊
    	1.請求來的時候 解析http數據幫你打包成一個字典傳輸給你 便於你操做各項數據
    	2.響應走的時候 自動幫你把數據再打包成符合http協議格式的樣子 再返回給前端
    
3.封裝路由與視圖函數對應關係 以及視圖函數文件 網站用到的全部的html文件所有放在了templates文件夾下
    1.urls.py 路由與視圖函數對應關係
    2.views.py 視圖函數 (視圖函數不僅僅指函數 也能夠是類)
    3.templates 模板文件夾
    
4.基於jinja2實現模板的渲染
	模板的渲染
		後端生成好數據 經過某種方式傳遞給前端頁面使用(前端頁面能夠基於模板語法更加快捷簡便使用後端傳過來的數據)

流程圖

小擴展

在不知道是要 encode 仍是 decode 的時候,能夠用一下方法

二進制數據對應的確定是 decode 解碼 成字符串呀

字符串對應的確定是 encode 編碼成二進制數據呀

數據類型轉換技巧(處理編碼)(數據 + encoding)

# 轉成 bytes 類型
bytes(data, encoding='utf-8')

# 轉成 str 類型
str(data, encoding='utf-8')

python三大Web主流框架分析對比

Django

大而全,自帶的功能特別特別多,就相似於航空母艦

**缺點:**有時過於笨重(小項目不少用不到)

Flask

短小精悍,自帶的功能特別少,全都是依賴於第三方組件(模塊)

第三方組件特別多 --> 若是把全部的第三方組件加起來,徹底能夠蓋過django

**缺點:**比較受限於第三方的開發者(可能有bug等)

Tornado

天生的異步非阻塞框架,速度特別快,可以抗住高併發

​ 能夠開發遊戲服務器(但開發遊戲,仍是 C 和C++用的多,執行效率更快)

手擼三大部分在框架中的狀況對比

前面的手擼推導過程,整個框架過程大體能夠分爲如下三部分

A:socket處理請求的接收與響應的發送

B:路由與視圖函數

C:模板語法給動態頁面渲染數據

Django

A:用的<u>別人</u>的 wsgiref 模塊 B:自帶路由與視圖函數文件 C:自帶一套模板語法

Flask

A:用的<u>別人</u>的werkzeug 模塊(基於 wsgiref 封裝的) B:自帶路由與視圖函數文件 C:用的<u>別人</u>的jinja2

Tornado

A,B,C全都有本身的實現

Django的下載安裝基本使用

參見個人另外一篇博客:Django-下載安裝-配置-建立django項目-三板斧簡單使用

原文出處:https://www.cnblogs.com/suwanbin/p/11520959.html

相關文章
相關標籤/搜索