基礎css
# HTTP響應狀態碼 10X:服務端已經接受到你的數據了 你能夠繼續提交數據進行下一步操做 20X:請求成功(200) 30X:重定向(301,302) 40X:請求錯誤(404) 50X:服務端錯誤(500) # GET請求與POST請求 GET請求:獲取頁面資源 POST請求:朝服務端發送數據(讓服務端校驗該數據)
1、Web框架本質html
全部的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端前端
根據不一樣的路徑返回不一樣的內容python
能夠寫幾個簡單頁面,而後經過http://127.0.0.1:8080/頁面名稱 來訪問對應的頁面測試mysql
import socket server = socket.socket() # 默認是TCP協議 server.bind(('127.0.0.1',8080)) # 綁定IP端口 server.listen(5) # 監聽 半連接池:保護計算機安全 while True: conn, addr = server.accept() # 等待鏈接 data = conn.recv(1024) # 接收客戶端信息 # 遵循HTTP協議,給迴應的消息加上響應狀態行 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') res = data.decode('utf-8') current_path = res.split('\r\n')[0].split(' ')[1] # 字符串切割,獲取路徑 # print(current_path) # 根據不一樣的路徑返回不一樣的內容 if current_path == '/index': # conn.send(b'index') with open('templates/111.html','rb') as f: conn.send(f.read()) elif current_path == '/login': conn.send(b'login') else: conn.send(b'404') conn.close()
瀏覽器訪問頁面請求信息:jquery
HTTP協議主要規定了客戶端和服務器之間的通訊格式nginx
響應相關信息能夠在瀏覽器調試窗口的network標籤頁中看到。能夠根據view信息切割得到須要請求的頁面web
請求首行 b'GET / HTTP/1.1\r\n 請求頭 Host: 127.0.0.1:8080\r\n Connection: keep-alive\r\n Cache-Control: max-age=0\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\n Accept-Encoding: gzip, deflate, br\r\n Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n Cookie: csrftoken=3vPenhmlRQb8Tvl4okwYM0OZpDCl3P7rbxvfpRDOHJy1zUApw89ugxM6OZSxhIBM\r\n \r\n 請求體 '
http://127.0.0.1:8080/index
view展開:
根據不一樣的路徑返回不一樣頁面請求---函數版sql
import socket sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() # 將不一樣的內容部分封裝成函數 def index(url): # 讀取index.html頁面內容 with open("index.html",'rb',encoding="utf-8") as f: s = f.read() # 返回字節數據 return bytes(s,encoding="utf-8") def login(url): with open("login.html",'rb',encoding="utf-8") as f: s = f.read() return bytes(s, encoding="utf-8") list1= [ ("templates/111.html","/index"), ("templates/login.html",'/login'), ] while True: # 等待鏈接 conn,add = sk.accept() data = conn.recv(1024) # 接收客戶端發來的消息 # 從data 中獲取路徑 data = str(data,encoding='utf-8') # 把收到的字節類型數據轉換成字符串 print("data>>>",data) # 按\r\n切割,url是從瀏覽器發過來的消息中分離出來的訪問路徑 url = data.split("\r\n")[0].split(' ')[1] print("url>>>>",url) conn.send(b'HTTP/1.1 200 OK\r\n\r\n') #遵循http協議,因此回覆的消息也要加狀態行 # 根據不一樣的路徑返回不一樣內容,reponse是具體的響應體 func = None for i in list1: if i[0].split("/")[1] == url: func = i[1] break # print("func>>>",func) if func: reponse = func(url) else: reponse = b"404 not found!" conn.send(reponse) conn.close() # 還有點問題//TODO
2、服務器程序和應用程序 數據庫
對於真實開發中的python web程序來講,通常會分爲兩部分:服務器程序和應用程序。
服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的各類數據進行整理。
應用程序則負責具體的邏輯處理。爲了方便應用程序的開發,就出現了衆多的Web框架,例如:Django、Flask、web.py等。不一樣的框架有不一樣的開發方式,可是不管如何,開發出的應用程序都要和服務器程序配合,才能爲用戶提供服務。
WSGI(Web Server Gateway Interface)就是一種規範,它定義了使用Python編寫的web應用程序與web服務器程序之間的接口格式,實現web應用程序與web服務器程序間的解耦
經常使用的WSGI服務器有uwsgi、Gunicorn。而Python標準庫提供的獨立WSGI服務器叫wsgiref,Django開發環境用的就是這個模塊來作服務器。
1.wsgiref 模塊
利用wsgiref模塊來替換咱們本身寫的web框架的socket server部分
# 未拆分前代碼 # http://127.0.0.1/index訪問對應的名稱到對應的頁面 from wsgiref.simple_server import make_server def index(): return 'index' def reg(): return 'res' def login(): return 'login' def error(): return '404' urls = [ ('/index',index), ('/reg',reg), ('/login',login), ] def run(env,reponse): reponse('200 OK', []) # 固定格式 print(env) # 將http格式的數據處理完畢,造成一個字段給你調用 current_path = env.get('PATH_INFO') # if current_path == '/index': # return [b'index'] func = None for url_tuple in urls: if current_path == url_tuple[0]: func = url_tuple[1] # 若是路由匹配上了,就回去對應的函數 break if func: res = func() else: res = error() return [res.encode('utf-8')] if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) # 一直監聽地址,只要有請求,就會給最後的函數或對象調用:run()執行 server.serve_forever()
# urls.py 存放訪問連接後的頁面 from views import * urls = [ ('/index',index), ('/reg',reg), ('/login',login), ] # views.py 存放訪問頁面函數 def index(): return 'index' def reg(): return 'res' def login(): return 'login' def error(): return '404' # wsgiref.py存放啓動 from wsgiref.simple_server import make_server from urls import urls from views import * def run(env,response): response('200 OK', []) # 固定格式 不需掌握 print(env) # 將http格式的數據處理完畢 造成一個字段給你調用 current_path = env.get('PATH_INFO') func = None for url_tuple in urls: if current_path == url_tuple[0]: func = url_tuple[1] # 若是路由匹配上了 就回去對應的函數 break if func: res = func(env) else: res = error(env) return [res.encode('utf-8')] if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) server.serve_forever()
根據拆分後的代碼,若是須要再添加訪問頁面,只須要在urls.py(路由與視圖函數的映射關係)和views.py(視圖函數)中增長對應的連接和函數就能夠
2.動靜態頁面
靜態網頁:數據是寫死的,一直不變
動態網頁:數據實時獲取的,一直在改變(eg:數據庫的數據或當前時間)
2.1獲取時間並顯示在頁面上:
# 在上面拆分代碼的基礎上 # urls.py增長 urls = [ ('/index',index), ('/reg',reg), ('/login',login), ('/get_time',get_time), ] # 對象視圖views.py裏增長函數 import time def get_time(): with open('templates/show_time.html','r',encoding='utf-8') as f: data = f.read() current_time = time.strftime('%Y-%m-%d %X') res = data.replace('timekkk',current_time) # 字符串替換 return res 而後運行wsgiref.py就能夠看到頁面上顯示動態的時間了,每次刷新時間都會變化
2.2 給前端傳字典而且字典能夠取值
# urls.py中新增對應訪問路徑 from view2 import * urls2 = [ ('/index', index), ('/reg', reg), ('/login', login), ('/get_time', get_time), ('/get_user', get_user), ] # views.py中新增對應函數 from jinja2 import Template def get_user(env): user_dict = {'username': 'simon', 'password': '123'} with open('templates/get_user.html', 'r', encoding='utf-8') as f: data = f.read() tmp = Template(data) # 實例化產生對象 res = tmp.render(data=user_dict) # 將user_dict傳遞給前端頁面,前端頁面用過變量名data就可以拿到user_dict字典 return res # html頁面body中設置 {#傳data這裏就寫data#} {{ data }} {#獲取帳號密碼#} <p>{{data.username}}</p> <p>{{data['password']}}</p>
<p>{{data.hobby.0}}</p>
<p>{{data.hobby.1}}</p>
模板渲染(雛形)
後端產生的數據直接傳遞給前端頁面,前端頁面獲取數據經過模板語法展現
模板語法:
{{}} 獲取後端傳遞的數據,經過變量名(變量名相關的)
{%%} 與邏輯相關的使用這個語法
jinja2模板語法極爲接近後端python語法
{{ data }}
<p>{{data.username}}</p>
<p>{{data['password']}}</p>
<p>{{data.hobby.0}}</p>
<p>{{data.hobby.1}}</p>
邏輯相關:
{%for user_dict in user_list%}
<tr>
<td>{{user_dict.id}}</td>
<td>{{user_dict.username}}</td>
<td>{{user_dict.password}}</td>
</tr>
{%endfor%}
2.3 數據庫取值頁面顯示
#urls2.py from view2 import * urls2 = [ ('/get_data',get_data), ] # view2.py 新增函數 from jinja2 import Template import pymysql def get_data(env): conn = pymysql.connect( host = '127.0.0.1', port = 3306, user = 'root', password = '123', database = 'test', charset = 'utf8', autocommit = True ) cursor = conn.cursor(pymysql.cursors.DictCursor) cursor.execute('select * from userinfo') res = cursor.fetchall() with open('templates/get_data.html','r',encoding='utf-8') as f: data = f.read() tmp = Template(data) res1 = tmp.render(user_list = res) return res1 # simple_server.py模塊,和以前的沒什麼變化 from wsgiref.simple_server import make_server from urls2 import urls2 from view2 import * def run(env,reponse): reponse('200 OK', []) # 固定格式 print(env) # 將http格式的數據處理完畢,造成一個字段給你調用 current_path = env.get('PATH_INFO') # if current_path == '/index': # return [b'index'] func = None for url_tuple in urls2: if current_path == url_tuple[0]: func = url_tuple[1] # 若是路由匹配上了,就回去對應的函數 break if func: res = func(env) else: res = error(env) return [res.encode('utf-8')] if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) # 一直監聽地址,只要有請求,就會給最後的函數或對象調用:run()執行 server.serve_forever() # get_data.html前端頁面代碼 # body內容 <table> <thead> <tr> <th>id</th> <th>username</th> <th>password</th> </tr> </thead> <tbody> {%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>
2.4 web服務渲染流程
根據早上的流程,咱們能夠劃出下面這個圖
2.5 web框架
python主流三大框架:
a.socket服務
b:路由與視圖函數映射關係
c:模板渲染
django:大而全 相似航空母艦
a.用的別人的 wsgiref 上線以後會換成uwsgi;默認併發1000多,本身能夠加nginx之類處理
b.本身寫的
c.本身寫的
flask:小而精,輕量級框架
a用的別人的 werkzeug
b本身寫的
c用的別人 jinja2
tornado:異步非阻塞
三者都是本身寫的
3、Django簡介
1.Django安裝與注意事項
# 主意事項 1.計算機名稱不能含有中文 2.一個pycharm窗口就是一個工程(項目) 3.項目文件夾不要有中文 # ps:django版本: django 1.X(如今用的版本是這個1.11.11) # 安裝 pip3 install django # 或pycharm直接安裝,能夠指定版本specify version
# 若是已經安裝了高版本須要下降版本:pip3 uninstall django,而後從新指定安裝:pip3 install django ===1.11.20 或pycharm指定版本安裝 # 查看djiango是否安裝成功 命令行界面:django-admin # 命令行建立django項目 django-admin startproject 項目名 ps:建立一個應用面的文件夾,裏面有一個跟應用名同名的文件夾和一個manage.py的文件 # 命令行建立應用 django-admin startapp 應用名 # application 一個django項目 能夠有多個應用,django是一款開發應用的web框架 django項目就相似是一所大學,而裏面的應用就相似於一個個學院 # 命令行啓動項目 python manage.py runserver 啓動成功後瀏覽器能夠訪問:http://127.0.0.1:8000和http://127.0.0.1:8000/admin ps:命令行建立django項目不會自動新建templates文件夾,而且settings.py配置文件(TEMPLATES 列表中DIRS)不會自動寫templates文件夾路徑,因此都須要手動添加[os.path.join(BASE_DIR,'templates')]
以下圖: # pycharm建立 項目:File-->New Project-->Django-->Location(建立項目)-->More Settings建立應用--->Application name:應用名 在pycharm的命令行中建立應用:Tools-->Run manage.py TASK-->startapp 應用名 應用建立後須要再settings.py中註冊應用INSTALLED_APPS裏添加 啓動後能夠訪問:http://127.0.0.1:8000 # 注意: 1 在django中建立的應用必須去settings文件中註冊才能生效,不然django不識別 2 確保不要端口衝突
2.Django項目目錄結構
項目名
應用名文件夾
migrations文件夾
數據庫遷移記錄
admin.py
django admin後臺管理相關
models.py
模型類
views.py
視圖函數
項目同名文件夾
settings.py
django暴露給用戶可配置的配置文件
urls.py
路由與視圖函數映射關係
templates
全部的html文件
manage.py
django入口文件
3.Django 必會三板斧
# django小白必會三板斧 # HttpResponse:返回字符串 # views.py def index(request): return HttpResponse("Hello Django index") # render:返回html頁面 def login(request): return render(request,'login.html') # redirect:重定向 def home(request): return redirect('https://www.baidu.com') # urls.py配置文件中加對應訪問路徑 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('login/', views.login), path('home/', views.home), ]
4.靜態文件配置
# 動態實時監測到前綴的變化 login.html <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script> {% load static %} <link href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}" rel="stylesheet"> <script src={% static "bootstrap-3.3.7/js/bootstrap.min.js" %}></script> </head> #用上述方法settings.py中接口前綴隨便修改,也不須要修改html中的對應前綴 # settings.py # 接口前綴:要想訪問靜態資源必須static打頭: # <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script> STATIC_URL = '/static/' # 新增文件放置路徑 STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static'), os.path.join(BASE_DIR,'static1'), os.path.join(BASE_DIR,'static2'), ]
例:登陸功能簡單實現
# form表單默認是get請求 get請求攜帶的參數是拼接在url後面的以?開頭&連接,默認method方式爲Get ps:get請求能夠攜帶參數 可是參數的大小有限制 最大4KB,而且是明文的 http://127.0.0.1:8000/login/?username=simon&password=123 # 若是改成method改成post提交,須要將settings.py中一行註釋,不然會報403錯誤: # 'django.middleware.csrf.CsrfViewMiddleware', # 跨站請求僞造 獲取用戶輸入的框 都必需要有name屬性 action參數有三種寫法 1.什麼都不寫 默認往當前頁面的url地址提交 2.只寫路由後綴(******) <form action="/login/" method="post"> 3.寫全路徑 <form action="https://www.baidu.com" method="post">
# 數據後端獲取 #前端 <form action="" method="post"> <p>username:<input type="text" class="form-control" name="username"></p> <p>password:<input type="password" class="form-control" name="password"></p> <p>籃球<input type="checkbox" name="xxx" value="basketball"></p> <p>足球<input type="checkbox" name="xxx" value="football"></p> <p>冰球<input type="checkbox" name="xxx" value="ice"></p> <input type="submit" class="btn btn-success pull-right"> </form> # views.py:獲取訪問login頁面的method以及post提交的數據 def login(request): print(request.method) # 獲取當前請求方式 if request.method == 'POST': # 獲取post請求提交的數據 print(request.POST) # get請求默認拿列表最後一個值:如-獲取到2個username,取值永遠拿最後一個元素 username = request.POST.get('username') password = request.POST.get('password') # 還能夠在後面增長判斷帳號密碼判斷,之後經過數據庫來判斷傳遞的帳號密碼
if username == "simon" and password == "123":
return redirect("http://www.xiaohuar.com")
return "xxxxxxx" hobby = request.POST.getlist('xxx') print(hobby,type(hobby)) print(username,type(username)) print(password, type(password)) return render(request,'login.html') # 結果: POST <QueryDict: {'username': ['simon'], 'password': ['123'], 'xxx': ['basketball', 'football', 'ice']}> ['basketball', 'football', 'ice'] <class 'list'> simon <class 'str'> 123 <class 'str'>