Web框架 Web框架可以簡單的理解為是基於互聯網的Web服務端>>>:socket服務端 1.WeB框架本質認識 1.我們可以這樣理解:我們所寫的Web框架其實就是一個socket服務端,而且用戶的瀏覽器就是一個socket客戶端。 2.本質上:瀏覽器是一個socket客戶端,伺服器是一個sock ...
目錄
- Web框架
- 基於SOCKET寫一個web應用(純手擼web框架)
- jinja2模塊
- 前端、後端和資料庫三者聯動
- python主流框架web框架
- django框架簡介
- 命令創建django項目
- django小白必會三板斧
Web框架
Web框架可以簡單的理解為是基於互聯網的Web服務端>>>:socket服務端
1.WeB框架本質認識
1.我們可以這樣理解:我們所寫的Web框架其實就是一個socket服務端,而且用戶的瀏覽器就是一個socket客戶端。
2.本質上:瀏覽器是一個socket客戶端,伺服器是一個socket服務端
2.MVC設計模型
我們先對 MVC 設計模式進行介紹,它是 Web 設計模式的經典之作,MTV 模式也是在它的基礎上衍生而來。
MVC 是 Model-View-Controller 的縮寫,其中每個單詞都有其不同的含義:
Modle 代表數據存儲層,是對數據表的定義和數據的增刪改查;
View 代表視圖層,是系統前端顯示部分,它負責顯示什麼和如何進行顯示;
Controller 代表控制層,負責根據從 View 層輸入的指令來檢索 Model 層的數據,併在該層編寫代碼產生結果並輸出。
3.MVC 設計模式的請求與響應過程
用戶通過瀏覽器向伺服器發起 request 請求,Controller 層接受請求後,同時向 Model 層和 View 發送指令;
Mole 層根據指令與資料庫交互並選擇相應業務數據,然後將數據發送給 Controller 層;
View 層接收到 Controller 的指令後,載入用戶請求的頁面,並將此頁面發送給 Controller 層;
Controller 層接收到 Model 層和 View 層的數據後,將它們組織成響應格式發送給瀏覽器,瀏覽器通過解析後把頁面展示出來。
4.Django的MTV設計模型
Django 借鑒了經典的MVC 模式,它將交互的過程分為3個層次,也就是MTV設計模式;
Model:數據存儲層,處理所有數據相關的業務,和資料庫進行交互,並提供數據的增刪改查;
Template:模板層(也叫表現層)具體來處理頁面的顯示;
View:業務邏輯層,處理具體的業務邏輯,它的作用是連通Model 層和 Template 。
5.djangoMTV設計模式的請求與響應過程
用戶通過瀏覽器對伺服器發起 request 請求,伺服器接收請求後,通過 View 的業務邏輯層進行分析,同時向 Model 層和 Template 層發送指令;
Mole 層與資料庫進行交互,將數據返回給 View 層;
Template 層接收到指令後,調用相應的模板,並返回給 View 層;
View 層接收到模板與數據後,首先對模板進行渲染(即將相應的數據賦值給模板),然後組織成響應格式返回給瀏覽器,瀏覽器進行解析後並最終呈現給用戶。
6.HTTP協議
超文本傳輸協議:規定了瀏覽器與伺服器之間數據交互的格式
HTTP協議的四大特性:
1.基於請求響應 -- 瀏覽器給服務端發起請求,服務端收到後做出回應
2.基於TCP、IP協議作用於應用層之上的協議
3.無狀態 -- 不保存用戶端的登錄狀態,見你千百遍我都當你如初見
4.無(短)連接 -- 一次請求響應後即斷開連接
HTTP協議的數據傳輸格式:
1.請求數據格式:
請求首行(請求方法...)
請求頭(一大堆K:V鍵值對)
\r\n ---換行
請求體(並不是所有的請求方法都有 主要用來攜帶敏感性數據)
2.響應數據格式:
響應首行(響應狀態碼...)
響應頭(一大堆k:v鍵值對)
\r\n ---換行
響應體(展示給用戶的數據)
post與get請求方法:
1.get請求
朝別人索要數據
2.post請求
朝別人提交數據
>>>上述兩種請求都可以攜帶額外的參數<<<
get請求攜帶數據的方式:
url?username=jason&hobby=mn
post請求攜帶數據的方式:
數據是放在請求體裡面的
基於SOCKET寫一個web應用(純手擼web框架)
1.實現最簡單的socket服務端
點擊查看代碼
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
sock , address = server.accept()
data = sock.recv(1024)
# print(data.decode('utf8'))
sock.send(b'HTTP/1.1 200 ok\r\n\r\n')
target_url = data.decode('utf8').split(' ')[1] # 按照空格切割,然後拿去切割後得第二個數據,拿到的就是我們輸入後臺網站的尾碼
if target_url == '/index':
sock.send(b'index view')
elif target_url == '/login':
sock.send(b'login view')
elif target_url == '/reg':
sock.send(b'reg view')
else:
sock.send(b'404 error')
1.socket服務端代碼
2.HTTP協議
3.根據網址尾碼的不同請求不同的內容
4.請求方式
GET:朝服務端索要數據
POST:朝服務端提交數據
5.從請求數據格式中篩選出用戶輸入的網址尾碼(從字元串中截取出來需要得內容)
target_url = data.decode('utf8').split(' ')[1]
6.代碼的缺陷
1.socket代碼重覆編寫造輪子
2.針對請求數據格式的處理複雜且重覆
3.針對不同網址尾碼的匹配方式過於lowB
2.基於wsgiref模塊擼
wsgiref內部分裝了socket代碼和請求數據的處理
服務端代碼
import wsgiref
from wsgiref.simple_server import make_server
from urls import urls
from view import *
def run(request, response):
"""
:param request: 請求數據
:param response: 響應數據
:return: 返回給客戶端的數據
"""
response('200 ok',[])
# print(request) # 自動將請求數據全部處理成字典K:V鍵值對形式
target_path = request.get('PATH_INFO') # /login
# if target_path == '/index':
# return [b'index']
# elif target_path == '/login':
# return [b'index']
# elif target_path == '/reg':
# return [b'reg']
# else:
# return [b'404 not found']
func_name = None
for url_tuple in urls: # ('/index',index)
if url_tuple[0] == target_path:
func_name = url_tuple[1] # 先存儲匹配到的函數名
break # 一旦匹配到內容就立刻結束for迴圈 沒有必要繼續往下執行了
# for 迴圈結束以後,還需要判斷func_name是不是為None(有可能沒有匹配上)
if func_name:
res = func_name(request)
else:
res = error(request)
return [res.encode('utf8')] # 做統一編碼處理,這樣函數就只需要返回字元串即可,操作更簡單
if __name__ == '__main__':
server = make_server('127.0.0.1',8080, run) # 任何訪問127.0.0.1:8080的請求都會給第三個參數加括弧進行調用
server.serve_forever()
urls代碼
from view import *
urls = (
('/index', index),
('/login', login),
('/func', func)
)
view代碼
def index(request):
return 'index'
def login(request):
return 'login'
def error(request):
return '404'
def func(request):
with open(r'myhtml02.html', 'r') as f:
data = f.read()
return data
1.wsgiref模塊解決了兩個問題
1.socket代碼重覆編寫造輪子
2.針對請求數據格式的處理複雜且重覆
2.思考如何再次實現根據不同的網址尾碼返回不同的內容(函數化)
先從大字典中查找出記錄網址尾碼的鍵值對
1.不推薦使用連續的多個if判斷
2.針對麵條版的代碼首先應該考慮封裝成函數,封裝成函數以後的好處就是,之後如果要添加頁面的時候只需要再寫一個函數就可以了,如果要修改某個頁面,只需要找到對應的函數修改函數就可以了
3.想在函數里再獲取一些方法,想看一下前端發過來的到底是什麼方法,將request作為參數傳給函數run函數裡面的其他函數
4.現在我們在一個py文件里寫了好多功能(處理頁面請求的核心邏輯、對應關係、服務端的代碼),這樣太亂了,根據py文件中功能的不同劃分到不同的py文件中去
urls.py 對應關係
views.py 功能函數
start.py 啟動文件
templates文件夾 存儲html
3.動靜態網頁
動態網頁
頁面上的數據不是全部寫死的 有些是動態獲取(後端傳入)
靜態網頁
頁面上的數據直接寫死的 要想改變只能修改源碼
實際需求
後端代碼回去當前時間 然後讓前端頁面展示
1.字元串替換
2.將字典數據傳遞給html頁面並且想要在頁面上操作字典數據
我們無法自己實現>>>:在html頁面上使用類似於後端的語法操作數據
html代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<p>heiheihei</p>
</body>
</html>
views代碼
def get_time(request):
import time
ctime = time.strftime('%Y-%m-%d %H:%M:%S')
with open(r'templates/myhtml03.html', 'r', encoding='utf8') as f:
data = f.read()
# 如何將時間嵌入到html文件數據內,之後在返回給前端瀏覽器(字元串的替換)
data = data.replace('heiheihei', ctime)
return data
urls代碼
from views import *
urls = (
('/index', index),
('/login', login),
('/func', func),
('/get_time', get_time)
)
jinja2模塊
jinja2能夠讓我們在html文件內使用類似於後端的語法來操作各種數據類型
pip3 install jinja2
jinja2模板語法:
{{···}}
{%···%}
html代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<h1>{{ data }}</h1>
<h1>{{ data['name'] }}</h1>
<h1>{{ data.get('pwd') }}</h1>
<h1>{{ data.hobby }}</h1>
</body>
</html>
views代碼
from jinja2 import Template
def get_dict(request):
user_dict = {'name': 'jason', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
with open(r'templates/myhtml04.html', 'r', encoding='utf8') as f:
data = f.read()
temp = Template(data)
res = temp.render(data=user_dict) # 將字典傳遞給html頁面 頁面上通過data即可獲取(data僅僅是一個變數名)
return res
前端、後端和資料庫三者聯動
html代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<h1 class="text-center">數據展示</h1>
<div class="col-md-6 col-md-offset-3">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>主鍵</th>
<th>姓名</th>
<th>年齡</th>
</tr>
</thead>
<tbody>
{% for user in user_data %}
<tr>
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
views代碼
import pymysql
def get_mysql(request):
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='123456',
database='day55',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from userinfo'
cursor.execute(sql)
user_data = cursor.fetchall() # [{},{},{}]
with open(r'templates/myhtml05.html','r',encoding='utf8') as f:
data = f.read()
temp = Template(data)
res = temp.render(user_data=user_data)
return res
點擊查看代碼
create database day55;
use da55
create table userinfo(id int primary key auto_increment,name varchar(32),age int);
insert into userinfo(name, age) values('jason',18),('kevin',29),('tony',20);
web框架就是統籌前後端,實現頁面的訪問
html代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<a href="/index">index</a>
<a href="/login">login</a>
<a href="/register">register</a>
<a href="/get_time">get_time</a>
<a href="/get_dict">get_dict</a>
<a href="/get_mysql">get_mysql</a>
</body>
</html>
views代碼
def home(request):
with open(r'templates/myhtml06.html','r',encoding='utf8') as f:
data = f.read()
return data
python主流框架web框架
django框架
大而全 自身攜帶的功能非常的多 類似於航空母艦
缺陷:開發小項目的時候使用該框架有點笨重(大材小用)
flask框架
小而精 自身攜帶的功能非常的少 類似於特種兵 主要依賴於第三方模塊
缺陷:受限於第三方模塊的開發
tornado框架
非同步非阻塞 該框架快到可以作為游戲伺服器
缺陷:上手難度是三者最高的
fastapi框架、sanic框架、...
最近流行的 抽空可以看看
三大主流web框架特點
django:
socket部分用的是別人的 wsgiref模塊
路由與視圖函數對應關係(路由匹配)用的是自己的
模版語法用的是自己的(沒有jinja2好用 但是也很方便)
flask:
socket部分用的是別人的 werkzeug(內部還是wsgiref模塊)
路由與視圖函數對應關係(路由匹配)自己寫的
模版語法用的別人的(jinja2)
tornado:
socket部分,路由與視圖函數對應關係(路由匹配),模版語法都是自己寫的
"""
框架雖然多 但是內部邏輯大差不差 我們重點學習一個即可>>>:django
如果你是小白切記不要同時學習上述框架
"""
django框架簡介
1.版本問題
1.X:同步 1.11
2.X:同步 2.2
3.X:非同步 3.2
ps:你無論使用什麼版本都可以 區別不大 2.2
2.啟動註意事項
1.電腦名稱儘量不要有中文
2.項目中所有的py文件名儘量不要用中文
3.不同版本的python解釋器配合不同版本的django 會有一些報錯
仔細查找一下報錯信息 裡面會提示你是哪個py文件裡面的代碼出錯
找到那一行代碼 把逗號刪除即可
widgets.py 152
4.一個pycharm視窗只允許有一個項目 不要做項目的嵌套
3.驗證django是否下載成功
cmd終端輸入django-admin
1.正常運行Django項目所需要知道的註意事項
1.電腦的名稱不能有中文,不然bug在哪你都不知道!
2.一個pycharm視窗只開一個django項目
在pycharm視窗只能有一個django在運行狀態,如果多開永遠只有第一個在運行,且一個pycharm視窗就是一個項目,不要在視窗下麵的子文件夾創建項目,不要和其他項目併列。
3.項目裡面所有的文件也儘量不要出現中文
使用中文名極容易出現莫名其妙的報錯,使用拼音也會顯得非常不專業
4.驗證django是否下載成功
cmd終端輸入django-admin
命令創建django項目
1.命令創建
1.命令行創建項目
D:\>django-admin startproject mysite
2.啟動django項目
1.先切換到項目目錄下
cd 項目名
2.執行啟動目錄
python manage.py runserver ip:port
3.訪問django服務端
瀏覽器直接訪問
4.創建app應用
django框架類似於是一個空殼子 給你提供所需的資源
至於到底要寫哪些功能 需要通過創建app來劃分
eg:django初始項目可以看成是一所大學
app就相當於是大學裡面的各個學院
python manage.py startapp 應用名
2.pycharm創建
滑鼠點點點即可
修改埠號
修改之後,重新啟動,就已經更改了埠號了,這就就可以運行好多個埠號
3. django目錄結構
項目同名文件夾
__init__.py 很少用 主要做一些冷門配置
settings.py 項目配置文件
urls.py 對應關係(目前簡單的理解:網址尾碼跟函數名)
wsgi.py django服務 基本不用
manage.py
django入口文件
templates文件夾
存儲項目所需的html文件
應用名文件夾(可以有多個)
migrations文件夾 orm相關(資料庫打交道的記錄)
__init__.py 很少用 主要做一些冷門配置
admin.py django自帶的後臺管理
apps.py 創建應用之後用於應用的註冊
models.py 存儲與資料庫表相關的類
tests.py 自帶的測試文件
views.py 存儲業務相關的邏輯代碼(函數、類)
db.sqlite3
自帶的小型資料庫
核心目錄結構
urls.py 路由層
views.py 視圖層
templates 模板層
models.py 模型層
django小白必會三板斧
HttpResponse:主要用於直接返回字元串類型的數據
render:主要用於返回html頁面 並且支持模板語法
redirect:主要用於頁面重定向
1.django自帶了一個功能:admin
2.創建功能
HttpResponse直接返回字元串類型的數據
urls代碼
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
views代碼
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def index(request):
return HttpResponse('你好啊 我是django2.2.22版本')
render用於返回html頁面 並且支持模板語法
templates環境變數問題
views代碼
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def index(request):
return HttpResponse('你好啊 我是django2.2.22版本')
def func(request):
return render(request,'func.html')
urls代碼
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('func/', views.func),
]
html代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<p>我是render</p>
<p>{{ data }}</p>
</body>
</html>
redirect主要用於頁面重定向
urls代碼
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('func/', views.func),
path('login/', views.login,
]
views代碼
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def index(request):
return HttpResponse('你好啊 我是django2.2.22版本')
def func(request):
user_dict = {'name': 'jason', 'pwd': 123}
return render(request, 'func.html', {'data': user_dict})
def login(request):
return redirect('http://www.baidu.com/')