[TOC]
>[success] # 嘗試搭建框架
~~~
我們所要做的工程目錄劃分
1.一個db 文件夾用來存儲數據
2.一個models 文件夾用來操作數據
3.一個static文件夾用來保存靜態文件
4.一個templates 用來保存html
5.一個routes.py 用來做路由映射
6.一個server.py 用來做啟動文件
7.一個utils.py 用來配置log
~~~
>[info] ## 編寫記錄log -- utils.py
~~~
import time
def log(*args, **kwargs):
# time.time() 返回 unix time
format = '%Y/%m/%d %H:%M:%S'
value = time.localtime(int(time.time()))
dt = time.strftime(format, value)
print(dt, *args, **kwargs)
~~~
>[info] ## 編寫服務器入口文件--server.py
~~~
1.Request 類進行,保存不同路由映射函數信息
2.response_for_path 處理run中獲取的地址進行路由映射
3.run 方法用來啟動server服務器
~~~
>[danger] ##### Request 保存路由映射對應請求信息類
~~~
1.初始化參數 method 記錄每一個映射路由的請求
2.path 記錄每一個路由的地址路徑
3.body 保存每一個路由的body 內容主要針對post
4.query 記錄每一個get請求鏈接上的參數 配合parsed_path 函數
5.form 用來處理post 請求參數urllib.parse .unquote(v) 處理v 是因為post 的時候空格是+
~~~
~~~
class Request:
def __init__(self):
self.method = "GET"
self.path = ""
self.body = ""
self.query = {}
def form(self):
args = self.body.split("&")
f = {}
for arg in args:
k, v = arg.split("=")
f[k] = urllib.parse .unquote(v)
return f
# 實例化對象
request = Reuqest()
~~~
>[danger] ##### parsed_path 處理get 請求
~~~
def parsed_path(path):
index = path.find("?")
if index == -1:
return path, {}
else:
path, query_string = path.split("?", 1)
args = query_string.split("&")
query = {}
for arg in args:
k, v = arg.split('=')
query[k] = v
return path, query
~~~
>[danger] ##### 編寫一個異常處理的erro文件返回404
~~~
def error(request, code=404):
e = {
404: b'HTTP/1.1 404 NOT FOUND\r\n\r\n<h1>NOT FOUND</h1>',
}
return e.get(code, b'')
~~~
>[danger] ##### response_for_path 處理路由映射關系
~~~
1.parsed_path用來處理 get 請求方法,將get 請求方法清洗,返回地址和請求參數
2.return 返回的是將路由映射保存的request 對象傳入到對應的映射方法
~~~
~~~
def response_for_path(path):
# 如果你是get
path, query = parsed_path(path)
request.path = path
request.query = query
r = {
"/static":route_static,
}
r.update(urls)
response = r.get(path, error)
return response(request)
~~~
>[danger] ##### run 啟動服務器文件
~~~
def run(host='', port=3000):
# 在控制臺打印端口,和服務器啟動時間
log('start at', '{}:{}'.format(host, port))
# 使用 with 可以保證程序中斷的時候正確關閉 socket 釋放占用的端口
with socket.socket() as s:
s.bind((host, port))
while True:
s.listen(5)
connection, address = s.accept()
r = b""
buffer_size = 1024
while True:
r_connection = connection.recv(buffer_size)
r += r_connection
if len(r_connection) <= 1024:
break
r = r.decode('utf-8')
if len(r.split())<2:
continue
# 拆分原始數據 獲取 請求方法和路徑 GET / HTTP/1.1
path = r.split()[1]
request.method = r.split()[0]
# 利用"\r\n\r\n" 是將請求體分割格式,獲取請求體
request.body = r.split("\r\n\r\n", 1)[1]
# 路由映射
response = response_for_path(path)
connection.sendall(response)
# 處理完請求, 關閉連接
connection.close()
~~~
>[info] ## 路由映射文件 -- routes.py
~~~
1.這個文件主要處理每一個,映射函數的請求
2.核對templates 文件的搭配
3.以及處理一些簡單的模板
~~~
>[danger] ##### 處理讀取HTML函數的 -- template
~~~
1.注意一定要對open 中的encoding 進行編碼,win默認是gbk模式
~~~
~~~
def template(name):
path = "template/" + name
with open(path, "r",encoding='utf-8') as f:
return f.read()
~~~
>[danger] ##### 配置url 參數映射字典
~~~
urls = {
'/': route_index,
'/login': route_login,
'/register': route_register,
'/messages': route_message,
}
~~~
>[danger] ##### 編寫靜態文件的映射函數 -- route_static
~~~
def route_static(request):
"""
兩種情況的處理
path, query = response_for_path('/static?file=doge.gif')
path '/static'
"""
filename = request.query.get('file', 'doge.gif')
path = 'static/' + filename
with open(path, 'rb') as f:
header = b'HTTP/1.1 200 OK\r\nContent-Type: image/gif\r\n'
img = header + b'\r\n'+ f.read()
return img
~~~
>[danger] ##### 編寫第一個主頁映射函數 -- route_index
~~~
def route_index(request):
"""
主頁的處理函數, 返回主頁的響應
"""
header = 'HTTP/1.1 210 VERY OK\r\nContent-Type: text/html\r\n'
body = template('index.html')
r = header + '\r\n' + body
return r.encode(encoding='utf-8')
~~~
>[danger] ##### 編寫登錄邏輯處理的---route_login
~~~
1.傳的參數中的request 保存的是每一個函數的,請求時候的處理信息
2.如果是post 請求處理創建的Request 類中form 方法保存的body中的內容
3.利用replace 替代我們在html 中特殊格式化的數據,這個頁面最后渲染不應該屬于任何請求,而是所有請求處理的展示內
容改變
~~~
~~~
def route_login(request):
header = 'HTTP/1.1 210 VERY OK\r\nContent-Type: text/html\r\n'
if request.method == 'POST':
form = request.form()
u = User.new(form)
if u.validate_login():
result = '登錄成功'
else:
result = '用戶名或者密碼錯誤'
else:
result = ''
body = template('login.html')
body = body.replace('{{result}}', result)
r = header + '\r\n' + body
return r.encode(encoding='utf-8')
~~~
>[danger] ##### 編寫注冊處理函數 --- route_register
~~~
def route_register(request):
header = 'HTTP/1.1 210 VERY OK\r\nContent-Type: text/html\r\n'
if request.method == 'POST':
# HTTP BODY 如下
# username=gw123&password=123
# 經過 request.form() 函數之后會變成一個字典
form = request.form()
u = User.new(form)
if u.validate_register():
u.save()
result = '注冊成功<br> <pre>{}</pre>'.format(User.all())
else:
result = '用戶名或者密碼長度必須大于2'
else:
result = ''
body = template('register.html')
body = body.replace('{{result}}', result)
r = header + '\r\n' + body
return r.encode(encoding='utf-8')
~~~
>[danger] ##### 模擬簡單的psot get請求 ---route_message
~~~
# message_list 存儲了所有的 message
message_list = []
def route_message(request):
log('本次請求的 method', request.method)
if request.method == 'POST':
form = request.form()
msg = Message.new(form)
log('post', form)
message_list.append(msg)
# 應該在這里保存 message_list
header = 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n'
body = template('html_basic.html')
# '#'.join(['a', 'b', 'c']) 的結果是 'a#b#c'
msgs = '<br>'.join([str(m) for m in message_list])
body = body.replace('{{messages}}', msgs)
r = header + '\r\n' + body
return r.encode(encoding='utf-8')
~~~
>[info] ## 編寫數據處理文件夾 model
~~~
1.我們處理數據庫的連接模塊進行拆分,成三個小py文件
2.__init__.py用來編寫model 的父類和數據存放方法
3.user.py 用來處理用戶信息判斷驗證
4.message.py 用來處理信息驗證
~~~
>[danger] # 編寫__init__文件
~~~
1.class Model 類用來處理文件的保存和讀取
--- 注意這個類幾點說明
--- db_path 中使用了cls.__name__ 的方法,可以獲取使用類的類名,因為類名和對象不同點在于,類名是唯一的,做成
父類后所有子類就變成唯一的
--- new 相當于創建了對應的類
--- all 是獲取了所有儲存文件的內容
--- save 將所有內容保存到文件目錄中
2.save 方法用來保存文件信息
3.load 用來加載文件信息
~~~
~~~
def save(data, path):
"""
本函數把一個 dict 或者 list 寫入文件
data 是 dict 或者 list
path 是保存文件的路徑
indent 是縮進
ensure_ascii=False 用于保存中文
"""
s = json.dumps(data, indent=2, ensure_ascii=False)
with open(path, 'w+', encoding='utf-8') as f:
log('save', path, s, data)
f.write(s)
def load(path):
"""
本函數從一個文件中載入數據并轉化為 dict 或者 list
path 是保存文件的路徑
"""
with open(path, 'r', encoding='utf-8') as f:
s = f.read()
log('load', s)
return json.loads(s)
# Model 是用于存儲數據的基類
class Model(object):
@classmethod
def db_path(cls):
classname = cls.__name__
path = 'db/{}.txt'.format(classname)
return path
@classmethod
def new(cls, form):
# 下面一句相當于 User(form) 或者 Msg(form)
m = cls(form)
return m
@classmethod
def all(cls):
"""
得到一個類的所有存儲的實例
"""
path = cls.db_path()
models = load(path)
log('log', models)
ms = [cls.new(m) for m in models]
return ms
def save(self):
"""
save 函數用于把一個 Model 的實例保存到文件中
"""
models = self.all()
log('models', models)
models.append(self)
# __dict__ 是包含了對象所有屬性和值的字典
l = [m.__dict__ for m in models]
log("lmodel", l)
path = self.db_path()
save(l, path)
def __repr__(self):
"""
對象的顯示形式,__dict__ 返回的是初始化 參數
"""
classname = self.__class__.__name__
properties = ['{}: ({})'.format(k, v) for k, v in self.__dict__.items()]
s = '\n'.join(properties)
return '< {}\n{} >\n'.format(classname, s)
~~~
>[danger] 用來進行用戶注冊登錄判斷的 user.py
~~~
from models import Model
class User(Model):
def __init__(self, form):
self.username = form.get('username', '')
self.password = form.get('password', '')
def validate_login(self):
return self.username == 'gua' and self.password == '123'
def validate_register(self):
return len(self.username) > 2 and len(self.password) > 2
~~~
>[danger] 用來進行簡單的post,get message.py
~~~
from models import Model
# 定義一個 class 用于保存 message
class Message(Model):
def __init__(self, form):
self.author = form.get('author', '')
self.message = form.get('message', '')
~~~
>[info] ## html 文件
>[danger] ##### login.html
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注冊登錄頁面</title>
</head>
<body>
<h1>登錄</h1>
<form action="/login" method="post">
<input type="text" name="username" placeholder="請輸入用戶名">
<br>
<input type="text" name="password" placeholder="請輸入密碼">
<br>
<button type="submit">登錄</button>
</form>
<h3>{{result}}</h3>
</body>
</html>
~~~
>[danger] ##### register.html
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注冊頁面</title>
</head>
<body>
<h1>注冊</h1>
<form action="/register" method="post">
<input type="text" name="username" placeholder="請輸入用戶名">
<br>
<input type="text" name="password" placeholder="請輸入密碼">
<br>
<button type="submit">注冊</button>
</form>
<h3>{{result}}</h3>
</body>
</html>
~~~
>[danger] ##### index.html
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>吃瓜主頁</title>
</head>
<body>
<h1>吃瓜</h1>
<a href="/login">Login</a>
<img src="/static?file=doge.gif"/>
<img src="/static?file=doge1.jpg"/>
<img src="/static?file=doge2.gif"/>
</body>
</html>
~~~
>[danger] ##### html_basic.html
~~~
<!DOCTYPE html>
<!-- 注釋是這樣的, 不會被顯示出來 -->
<!--
html 格式是瀏覽器使用的標準網頁格式
簡而言之就是 標簽套標簽
-->
<!-- html 中是所有的內容 -->
<html>
<!-- head 中是放一些控制信息, 不會被顯示 -->
<head>
<!-- meta charset 指定了頁面編碼, 否則中文會亂碼 -->
<meta charset="utf-8">
<!-- title 是瀏覽器顯示的頁面標題 -->
<title>例子 1</title>
</head>
<!-- body 中是瀏覽器要顯示的內容 -->
<body>
<!-- html 中的空格是會被轉義的, 所以顯示的和寫的是不一樣的 -->
<!-- 代碼寫了很多空格, 顯示的時候就只有一個 -->
很 好普通版
<h1>很好 h1 版</h1>
<h2>很好 h2 版</h2>
<h3>很好 h3 版</h3>
<!-- form 是用來給服務器傳遞數據的 tag -->
<!-- action 屬性是 path -->
<!-- method 屬性是 HTTP方法 一般是 get 或者 post -->
<!-- get post 的區別上課會講 -->
<form action="/messages" method="post">
<!-- textarea 是一個文本域 -->
<!-- name 屬性, 用處上課講 -->
<textarea name="message"></textarea>
<textarea name="author"></textarea>
<!-- button type=submit 才可以提交表單 -->
<button type="submit">POST 提交</button>
</form>
<form action="/messages" method="get">
<textarea name="message"></textarea>
<button type="submit">GET 提交</button>
</form>
{{messages}}
</body>
</html>
~~~
- 網絡原理
- 為搭建框架做準備
- 簡單認識網路
- 自定義模擬網站案例
- 優化最終框架
- 數據存儲 -- data
- 用戶個人信息存儲 -- User.txt
- 路由映射 -- routes
- 處理用戶信息 -- routes_static.py
- 保存靜態文件 -- static
- templates -- html 集中處理模塊
- 首頁 -- index.html
- 登陸 -- login.html
- 用戶注冊頁面 -- register
- 日志模塊 -- log.gua.txt
- 啟動文件--server.py
- orm處理 -- model.py
- 日志模塊 -- utils.py
- 兩種數據庫類型
- 傳統數據庫了解篇
- 前端快速入門
- JS簡單使用入門
- css簡單快速入門
- DJANGO
- virtualenv-創建虛擬環境
- 項目結構
- django-admin中文配置
- django-打印sql語句
- django-基礎
- 認識MVC和MTV
- Django--初識
- Django--初識案例
- Django-FBV/CBV
- Django--常用input 交互
- Django-url
- Django-url.py 配置
- Django-include 使用
- Django-url name
- Django-ORM
- ORM-數據庫配置
- ORM-model字段
- ORM-model字段解釋
- ORM-字段選項
- ORM-查詢
- ORM-四種常用查詢方法
- ORM-三種獲取數據
- ORM-其他查詢方式
- ORM-條件查詢雙線
- ORM-Q和F條件使用
- ORM-三種數據庫交互
- 案例 -- 一對多
- ORM-技巧/常見問題
- ORM-N+1 問題
- ORM-并發的處理
- ORM-數量查詢、
- ORM-正向反向查詢
- ORM-基礎案例一
- ORM-基礎一對多案例
- Django-templates
- Django-模板的繼承
- Django-模板的過濾
- Django-自定義模板的過濾
- Django-cookie
- Django-cookies 裝飾器
- Djang-session
- Django-CSRF
- Django-中間件 -- 后續了解
- Django- 緩存 -- 沒有深入了解
- Django-form
- From-ajax
- form-內部驗證處理
- form-屬性
- form-常用的標簽字段
- form-常用的下拉和選擇
- form-widget速查
- Django-ajax序列化
- Django-多種ajax寫法
- ajax-原生寫法
- ajax-$寫法
- ajax-ifram
- Django-ajax圖片上傳
- ajax-原始寫法
- ajax-正常寫法
- iframe+form
- 實戰寫法
- Django-常用自編寫組件
- Django-雙菜單組合搜索
- Django - 多菜單組合搜索
- Django-分頁
- django-綜合基礎
- 綜合基礎-render
- django-admin
- admin-頁面配置
- admin-字段配置
- admin-編輯頁面
- admin-forms驗證
- admin-創建抽象類
- django-驗證碼
- 驗證碼-第三方生成庫
- 驗證碼-view.py使用
- 驗證碼-注意引入Monaco.ttf
- django-用戶注冊
- 注冊-form 模塊
- 注冊-views 模塊
- 注冊-html模塊
- 注冊-model模塊
- django-用戶登錄三種
- session登錄
- form-session 寫法
- view-寫法
- Html-寫法
- model-寫法
- 繼承類登錄
- 外鍵關聯登錄
- django-簡單的student 管理案例
- app-urls.py
- app-models.py配置
- admin-admin.py配置
- app-form.py 和數據庫關聯的寫法
- app-FBV_views.py
- app-CBV_views.py
- templates-index.html
- django-博客系統
- APP目錄-models.py 創建
- APP目錄-基礎展示數據分析
- APP目錄-基礎數據展示cls
- ListView
- DetailView
- FormView
- 額外功能拓建
- 添加文章搜索/用戶文章查詢功能
- 增加一個友情鏈接
- 增加一個評論模塊
- App-利用Bootstrap4 搭建樣式
- 項目crm
- 思維導圖
- perfectCRM-項目名字
- settings.py-配置
- view.py-登陸/登出函數
- crm-app文件
- model.py-表的創建
- admin.py-注冊后臺
- view.py-視圖層
- static-靜態文件
- css
- bootstrap.min.css
- dashboard.css
- ie10-viewport-bug-workaround.css
- signin.css
- fonts
- imgs
- js
- jquery.js
- bootstrap.min.js
- holeder.js
- ie10-viewport-bug-workaround.js
- ie-emulation-modes-warning.js
- plugins
- html模板文件-templates
- crm
- index.html-首頁模板