dya49:django:wsgrief&模板渲染Jinjia2&django的MTV/MVC框架&創建/啟動一個django項目
- 2020 年 9 月 9 日
- 筆記
- PythonS31-筆記, Python全棧31期-筆記
目錄
自定義web框架wsgiref版
1.wsgiref構建服務端
wsgiref本身就是個web框架,提供了一些固定的功能(請求和響應資訊的封裝),
有了wsgiref我們就不需要自己寫原生的socket了
也不需要咱們自己來完成請求資訊的提取了
整體結構和socketserver類似
from urllib.parse import parse_qs from wsgiref.simple_server import make_server import webauth def application(environ, start_response): # start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')]) # start_response('200 OK', [('Content-Type', 'text/html'),('charset','utf-8')]) start_response('200 OK', [('Content-Type', 'text/html')]) print(environ) print(environ['PATH_INFO']) path = environ['PATH_INFO'] #用戶獲取login頁面的請求路徑 if path == '/login': with open('web.html','rb') as f: data = f.read() #針對form表單提交的auth路徑,進行對應的邏輯處理 elif path == '/auth/': #登陸認證 #1.獲取用戶輸入的用戶名和密碼 #2.去資料庫做數據的校驗,查看用戶提交的是否合法 # user_information = environ[''] if environ.get("REQUEST_METHOD") == "POST": #獲取請求體數據的長度,因為提交過來的數據需要用它來提取,注意POST請求和GET請求的獲取數據的方式不同 try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 #POST請求獲取數據的方式 request_data = environ['wsgi.input'].read(request_body_size) print('>>>>>',request_data) # >>>>> b'username=chao&password=123',是個bytes類型數據 print('?????',environ['QUERY_STRING']) #????? 空的,因為post請求只能按照上面這種方式取數據 #parse_qs可以幫我們解析數據 re_data = parse_qs(request_data) print('拆解後的數據',re_data) #拆解後的數據 {b'password': [b'123'], b'username': [b'chao']} #post請求的返回數據我就不寫啦 pass if environ.get("REQUEST_METHOD") == "GET": #GET請求獲取數據的方式,只能按照這種方式取 print('?????',environ['QUERY_STRING']) #????? username=chao&password=123,是個字元串類型數據 request_data = environ['QUERY_STRING'] # parse_qs可以幫我們解析數據 re_data = parse_qs(request_data) print('拆解後的數據', re_data) #拆解後的數據 {'password': ['123'], 'username': ['chao']} username = re_data['username'][0] password = re_data['password'][0] print(username,password) #進行驗證: status = webauth.auth(username,password) if status: # 3.將相應內容返回 with open('websuccess.html','rb') as f: data = f.read() else: data = b'auth error' # 但是不管是post還是get請求都不能直接拿到數據,拿到的數據還需要我們來進行分解提取,所以我們引入urllib模組來幫我們分解 #注意昂,我們如果直接返回中文,沒有給瀏覽器指定編碼格式,默認是gbk,所以我們需要gbk來編碼一下,瀏覽器才能識別 # data='登陸成功!'.encode('gbk') else: data = b'sorry 404!,not found the page' return [data] #和咱們學的socketserver那個模組很像啊 httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()
2.創建資料庫並插入數據
如果我們要做一個登陸註冊的一個介面,肯定要輸入用戶名和密碼,這時候肯定要涉及資料庫的操作了
so 我們在資料庫中創建一些數據
mysql> create database db1; Query OK, 1 row affected (0.00 sec) mysql> use db1; Database changed mysql> create table userinfo(id int primary key auto_increment,username char(20) not null unique,password char(20) not null); Query OK, 0 rows affected (0.23 sec) mysql> insert into userinfo(username,password) values('chao','666'),('sb1','222'); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from userinfo; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | chao | 666 | | 2 | sb1 | 222 | +----+----------+----------+ 2 rows in set (0.00 sec)
3.pymysql連接資料庫對資料庫進行操作
數據創建好了,我們現在想要用python對資料庫進行操作,所以需要pymysql來連接一下
#創建表,插入數據 def createtable(): import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='666', database='db1', charset='utf8' ) cursor = conn.cursor(pymysql.cursors.DictCursor) sql = ''' -- 創建表 create table userinfo(id int primary key auto_increment,username char(20) not null unique,password char(20) not null); -- 插入數據 insert into userinfo(username,password) values('chao','666'),('sb1','222'); ''' cursor.execute(sql) conn.commit() cursor.close() conn.close()
4.auth登錄驗證
現在有資料庫了,我們就可以對用戶名和密碼進行驗證了
在auth函數中傳入用戶輸入的用戶名和密碼,通過select查詢結果確定用戶名和面是否正確
#對用戶名和密碼進行驗證 def auth(username,password): import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123', database='db1', charset='utf8' ) print('userinfo',username,password) cursor = conn.cursor(pymysql.cursors.DictCursor) sql = 'select * from userinfo where username=%s and password=%s;' res = cursor.execute(sql, [username, password]) if res: return True else: return False
5.登錄頁面-login.html
在網頁上,我們要看到一個用戶名和密碼的輸入框,所以需要創建一個前端html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--如果form表單裡面的action什麼值也沒給,默認是往當前頁面的url上提交你的數據,所以我們可以自己指定數據的提交路徑--> <!--<form action="//127.0.0.1:8080/auth/" method="post">--> <form action="//127.0.0.1:8080/auth/" method="get"> 用戶名<input type="text" name="username"> 密碼 <input type="password" name="password"> <input type="submit"> </form> <script> </script> </body> </html>
6.登陸成功的跳轉介面
登錄成功後,有一個跳轉頁面,所以需要創建一個跳轉頁面的html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> h1{ color:red; } </style> </head> <body> <h1>寶貝兒,恭喜你登陸成功啦</h1> </body> </html>
自定義web框架wsgiref版-優化版
優化版和上面的版本有什麼不同?
對之前的版本進行優化,將不同的函數按照功能分別寫到不同的文件和文件夾中
下面是文件的一個結構圖:
關於上圖的解釋
1.static用於存放一些靜態文件
包括css js icon jpg圖片這種文件
2.template存放前端html文件
3.auth用來存放一些需要驗證的函數
import pymysql def check(username, pwd): conn = pymysql.connect( host='152.136.114.188', port=3306, user='root', password='123456', database='django', charset='utf8' ) cursor = conn.cursor() sql = 'select * from userinfo where username=%s and password=%s;' res = cursor.execute(sql, [username, pwd]) if res: return True else: return False
4.manage.py是用來實現執行命令的函數
這樣我們在pycharm命令行中通過 python manage.py xxx就可以執行相關命令了
from models import UserInfo from wsgi import run import sys args = sys.argv print(args) #['manage.py', 'migrate'] print(args[1]) if args[1] == 'migrate': obj = UserInfo() obj.create_model() elif args[1] == 'runserver': ip = args[2] port = int(args[3]) print(ip,port) # print(type(port)) run(ip, port) # python manage.py runserver 127.0.0.1 8001
5.models.py是和資料庫相關的
主要完成了用python連接mysql的相關配置資訊以及python對mysql進行一些增刪改查操作用的
class UserInfo: def create_model(self): import pymysql conn = pymysql.connect( host='152.136.114.188', port=3306, user='root', password='123456', database='django', charset='utf8' ) cursor = conn.cursor() sql = ''' create table userinfo(id int primary key auto_increment, username char(10), password char(10)); ''' cursor.execute(sql) conn.commit()
6.urls.py是用來確定url路徑的,並且通過訪問相應的路徑,可以執行和路徑相關的函數(view)
import views urlpatterns = [ ('/home', views.home), ('/login', views.login), ('/vip.html', views.vip), ('/favicon.ico', views.ico), ('/test.css', views.css), ('/test.js', views.js), ('/2.jpg', views.jpg), ]
7.views.py是用來實現主要邏輯的,和項目內容邏輯相關的函數都寫在這裡面
def home(environ): msg = {'name': 'chao', 'hobby': ['女人', 'ddj', '小電影']} # with open('./templates/index.html', 'rb') as f: # data = f.read() with open('./templates/index.html', 'r', encoding='utf-8') as f: data = f.read() t = Template(data) ret = t.render(msg) return ret.encode('utf-8')
8.wsgi.py是web框架的伺服器, 它代替了socket
from urls import urlpatterns from wsgiref.simple_server import make_server def run(ip, port): # print('xxxxxxxx') def application(environ, start_response): ''' :param environ: 是全部加工好的請求資訊,加工成了一個字典,通過字典取值的方式就能拿到很多你想要拿到的資訊 :param start_response: 幫你封裝響應資訊的(響應行和響應頭),注意下面的參數 :return: ''' path = environ['PATH_INFO'] for url in urlpatterns: if url[0] == path: data = url[1](environ) break else: data = b'404 page not found' start_response('200 OK', [('a', '1'), ]) return [data] httpd = make_server(ip, port, application) # print('Serving HTTP on port 8001...') # 開始監聽HTTP請求: httpd.serve_forever()
模板渲染JinJa2
如果我們想實現一個動態頁面
之前使用的方法是:
假設以時間為例,在前端頁面上顯示時間戳(刷新就會顯示當前時間戳)
怎麼做到這件事呢?
def html(environ): # 1.創建一個當前時間時間戳 current_time = str(time.time()) # 2.讀出當前的html文件 with open('./templates/home.html', 'r', encoding='utf-8') as f: data = f.read() # 3.將文件中的xxoo替換為時間戳 data = data.replace('xxoo', current_time).encode('utf-8') return data
在home.html中,搞一個字元串xxoo,然後時間戳就能夠替換上去了
<body> <!-- 在html文件中,寫一個標籤,其中的內容有xxoo --> <h1>皇家賭場--xxoo</h1> <a href="//127.0.0.1:8002/vip.html">會員中心</a> <img src="2.jpg" alt=""> <div class="c1" id="d1"></div> </body>
其實,這種行為從專業角度老說,叫做模板渲染
這個過程其實就是HTML模板渲染數據
本質上就是HTML內容中利用一些特殊的符號來替換要展示的數據。
我這裡用的特殊符號是我定義的
其實模板渲染有個現成的工具:JinJa2
用JinJa2實現動態介面
from jinja2 import Template def index(): with open("index2.html", "r",encoding='utf-8') as f: data = f.read() template = Template(data) # 生成模板文件 ret = template.render({"name": "于謙", "hobby_list": ["燙頭", "泡吧"]}) # 把數據填充到模板裡面 return [bytes(ret, encoding="utf8"), ]
在JinJa2中 特殊符號就是{{ }} or {% %}
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h1>姓名:{{name}}</h1> <h1>愛好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
上面.py中的數據是我們手動寫的
當然我們也可以從資料庫中獲取數據,但是前提一定要配置用pymysql配置好資料庫哦
MTV和MVC框架
MVC框架
Web伺服器開發領域裡著名的MVC模式,所謂MVC就是把Web應用分為模型(M),控制器(C)和視圖(V)三層,他們之間以一種插件式的、松耦合的方式連接在一起,模型負責業務對象與資料庫的映射(ORM),視圖負責與用戶的交互(頁面),控制器接受用戶的輸入調用模型和視圖完成用戶的請求,其示意圖如下所示:
MTV框架
Django的MTV模式本質上和MVC是一樣的,也是為了各組件間保持松耦合關係,只是定義上有些許不同,Django的MTV分別是指:
- M 代表模型(Model): 負責業務對象和資料庫的關係映射(ORM)。
- T 代表模板 (Template):負責如何把頁面展示給用戶(html)。
- V 代表視圖(View): 負責業務邏輯,並在適當時候調用Model和Template。
除了以上三層之外,還需要一個URL分發器,它的作用是將一個個URL的頁面請求分發給不同的View處理,View再調用相應的Model和Template,MTV的響應模式如下所示:
一般是用戶通過瀏覽器向我們的伺服器發起一個請求(request),這個請求回去訪問視圖函數,(如果不涉及到數據調用,那麼這個時候視圖函數返回一個模板也就是一個網頁給用戶),視圖函數調用模型,模型去資料庫查找數據,然後逐級返回,視圖函數把返回的數據填充到模板中空格中,最後返回網頁給用戶。
django:下載安裝&創建啟動
1.下載django
pip3 install django==1.11.9
2.創建一個django的project
django-admin startproject mysite # 創建了一個名為"mysite"的Django 項目:
當我們執行完這條指令後 ,會出現如下一堆文件
這些文件的作用:
- manage.py —– Django項目裡面的工具,通過它可以調用django shell和資料庫,啟動關閉項目與項目交互等,不管你將框架分了幾個文件,必然有一個啟動文件,其實他們本身就是一個文件。
- settings.py —- 包含了項目的默認設置,包括資料庫資訊,調試標誌以及其他一些工作的變數。
- urls.py —– 負責把URL模式映射到應用程式。
- wsgi.py —- runserver命令就使用wsgiref模組做簡單的web server,後面會看到renserver命令,所有與socket相關的內容都在這個文件裡面了,目前不需要關注它。
3.創建django APP應用
剛才我們只是創建了一個django項目,但是裡面並沒有之前所提到的models.py views.py這些文件
這是因為我們只是創建了django項目,並沒有創建一個django的app
所以這個app需要我們執行一條指令去創建
python manage.py startapp blog2 #創建一個django應用 每個應用的目錄下都有自己的views.py視圖函數和models.py資料庫操作相關的文件
當我們執行完這條指令後,會發現文件夾多了幾個文件
我們現在只需要看其中兩個文件
models.py :之前我們寫的那個名為model的文件就是創建表用的,這個文件就是存放與該app(應用)相關的表結構的
views.py :存放與該app相關的視圖函數的
其他的先不用管,以後會知道的
4.啟動django項目
python manage.py runserver 8080 # python manage.py runserver 127.0.0.1:8080,本機就不用寫ip地址了 如果連埠都沒寫,默認是本機的8000埠
這樣我們的django就啟動起來了。當我們訪問://127.0.0.1:8080/時就可以看到:
這是django里自己寫的一個html文件,當看到這個頁面就說明,我們的django啟動成功了