当前位置:职场发展 > django框架安装介绍

django框架安装介绍

  • 发布:2023-09-30 11:39

原文链接:https://www.sychzs.cn/maple-shaw/p/8862330.html

Web框架的本质

我们可以这样理解:所有的Web应用本质上都是一个socket服务器,而用户的浏览器是一个socket客户端。这样我们就可以自己实现web框架了。

进口插座
sk =socket.socket()
sk.bind(("127.0.0.1", 8000))
sk.listen()
同时 正确:
conn, addr = sk.accept()
数据 = conn.recv(8096)
conn.send(b"OK")
conn.close()
查看代码

sk.bind(("127.0.0.1", 8000)) 当绑定为8000时,浏览器报错; ERR_INVALID_HTTP_RESPONSE。无效回复,回复格式有问题

套接字服务器

  1. 进口插座
  2. sk = socket.socket()
  3. sk.bind(("127.0.0.1", 8000))
  4. sk.listen()
  5. 正确:
  6. conn, addr = sk.accept()
  7. 数据 = conn.recv(8096)
  8. conn.send(b"确定")
  9. conn.close()

如果把8000端口改成80,浏览器就能显示ok了,但是我们想要的是其他端口也能显示内容

可以说Web服务本质上就是基于这十几行代码进行扩展的。这段代码是他们的祖先。

用户在浏览器中输入URL,浏览器将向服务器发送数据。浏览器会发送什么数据?如何发送?谁来决定这个?如果你的网站遵循这个规则,他的网站也遵循他的规则,互联网还能用吗?

所以一定要有一个统一的规则,让大家在收发消息的时候有一个格式依据,不能随便写。

这个规则就是HTTP协议。以后无论是浏览器发送请求信息,还是服务器回复响应信息,都必须遵循这个规则。

HTTP协议主要规定了客户端和服务器之间的通信格式。那么HTTP协议是如何规定消息格式的呢?

首先打印我们在服务器上收到的消息。

  1. 进口插座
  2. sk = socket.socket()
  3. sk.bind(("127.0.0.1", 8000))
  4. sk.listen()
  5. 正确:
  6. conn, addr = sk.accept()
  7. 数据 = conn.recv(8096)
  8. print(data) #打印浏览器发送的消息
  9. conn.send(b"确定")
  10. conn.close()

输出:

接收到的是bytes类型,打印解码出来的是(string类型,换行符):

print(data.decode()) # 打印浏览器发送的消息

4 {IMG_4: Ahr0CHM6LY9PBWCYMDE4LMNUYMXVZ3MUY2JSB2JSB2CVMTI4NJUXMI8ymde5mdyvmti4njuxmDe5mDyxMTE2MZMTI0MZUZDQ2L nbuzw ==/}

b'GET / HTTP/1.1\r\n主机:127.0.0.1:8080\r\n连接:保持活动\r\n缓存控制:最大年龄=0\r\n升级不安全请求:1 \r\n用户代理:Mozilla/5.0(Windows NT 6.1;WOW64)AppleWebKit/537.36(KHTML,如 Gecko)Chrome/66.0.3355.4 Safari/537.36\r\n接受:text/html,application/xhtml+xml,application /xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n接受编码: gzip, deflate, br\r\n接受语言: zh-CN,zh;q=0.9 \r\nCookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8\r\n\r\n'

让我们将 \r\n 替换为换行符,以便更清楚地看到它:

  1. GET / HTTP/1.1
  2. 主机:127.0.0.1:8080
  3. 连接:保持活动
  4. 缓存控制:最大年龄=0
  5. 升级不安全请求:1
  6. 用户代理:Mozilla/5.0(Windows NT 6.1;WOW64)AppleWebKit/537.36(KHTML,如 Gecko)Chrome/66.0.3355.4 Safari/537.36
  7. 接受:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
  8. 接受编码:gzip、deflate、br
  9. 接受语言:zh-CN,zh;q=0.9
  10. Cookie:csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8

那么我们来看看访问博客园官网时浏览器收到的响应信息。

在浏览器调试窗口的网络选项卡中可以看到响应相关信息。并非所有响应数据都可以在查看源中查看

点击查看源码后,显示如下图:

响应是请求的数据主体部分。复制并粘贴到您创建的套接字中,然后将其发送到浏览器

发送到浏览器的内容为HTML时:conn.send(b"HTTP/1.1 200 OK\r\n\r\n

ok

")。渲染

我们发现发送和接收的消息需要遵循一定的格式。这里我们需要了解一下HTTP协议。

HTTP协议介绍

HTTP协议对发送和接收消息有格式要求

每个 HTTP 请求和响应都遵循相同的格式。 HTTP包含两部分:Header和Body,其中Body是可选的。

HTTP 响应头有一个 Content-Type 指示响应的内容格式。其值为text/html;字符集=utf-8。

text/html 表示是网页,charset=utf-8 表示编码为utf-8。

HTTP GET 请求格式:

HTTP响应格式:

自定义网络框架

经过上面的学习,我们将基于socket服务器上的十几行代码来编写自己的Web框架。我们不先处理浏览器发送的请求,而是让浏览器显示我们的Web框架返回的信息。然后我们要按照HTTP协议格式发送响应。

  1. 进口插座
  2. sock = socket.socket(www.sychzs.cn_INET, socket.SOCK_STREAM)
  3. sock.bind(('127.0.0.1', 8000))
  4. sock.listen()
  5. 同时正确:
  6. conn, addr = sock.accept()
  7. 数据 = conn.recv(8096)
  8. #在回复消息中添加回复状态行
  9. conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
  10. conn.send(b"确定")
  11. conn.close()

我们简单地用十几行代码演示了Web框架的本质。

让我们继续改进我们的自定义 Web 框架!

根据不同路径返回不同内容


就这样结束了吗?如何让我们的Web服务根据用户请求的URL返回不同的内容?

这是小菜一碟。我们可以从请求相关数据中获取请求URL的路径,然后利用该路径进行判断...

  1. “””
  2. 根据URL中不同的路径返回不同的内容
  3. “””
  4. 进口插座
  5. sk = socket.socket()
  6. sk.bind(("127.0.0.1", 8080)) #绑定IP和端口
  7. sk.listen() # 听力
  8. 同时正确:
  9. #等待连接
  10. conn,添加 = sk.accept()
  11. data = conn.recv(8096) # 接收客户端发来的消息
  12. #从数据中获取路径
  13. data = str(data,encoding="utf8") #将接收到的字节类型数据转换为字符串
  14. # 分割为 \r\n
  15. data1 = data.split("\r\n")[0]
  16. url = data1.split()[1] #url是我们从浏览器发送的消息中分离出来的访问路径
  17.   conn.send(b'HTTP/1.1 200 OK\r\n\r\n') #因为必须遵循HTTP协议,所以回复消息也必须添加状态行
  18. #根据不同路径返回不同内容
  19. if url == "/index/":
  20.     响应= b“索引”    
  21. elif url == "/home/":
  22.     回复= b“家”    
  23. 其他:
  24.     回复= b“404未找到!”
  25. conn.send(响应)
  26. conn.close()

当浏览器访问相应目录时,后台显示/home。我们需要根据访问的目录向浏览器发送不同的数据。

1 {IMG_15:Ahr0Chm6ly9pbwcymDe4LMNUYMXVZ3MUY2JSB2CVMTI4NJUXMI8ymDe5MDYVMTI4NJUXMI0YMDYXMTE2NTE2NTI5MC0XODGYMTI0OTM1 Lnbuzw ==/}

获取路径:

data = conn.recv(8096)
print(data.decode().split()) # 打印浏览器发送的消息

根据索引打印

print(data.decode().split()[1]) # 打印浏览器发送的消息

不用担心 favicon.ico,它是 Google Chrome 的标题

因为获取到的内容有斜线,而这里判断为没有斜线的字符串,所以没有匹配成功。如果是正规的,花多少钱都可以实现。

1 {IMG_19:Ahr0Chm6ly9pbwcymDe4LMNUYMXVZ3MUY2JSB2CVMTI4NJUXMI8ymDe5MDYVMTI4NJIMDE5MDYXMTE3MDG2NTCWNJMUC G5n/}

先发送请求头,再发送数据,分两部分发送。

根据不同路径返回不同内容--功能版

以上代码解决了不同URL路径返回不同内容的需求。

我们返回的内容就是几个简单的字符,那如果我可以将返回的结果封装成一个函数呢?

  1. “””
  2. 根据URL中不同路径返回不同内容--功能版本
  3. “””
  4. 进口插座
  5. sk = socket.socket()
  6. sk.bind(("127.0.0.1", 8080)) #绑定IP和端口
  7. sk.listen() # 听力
  8. #将返回的不同内容部分封装到函数中
  9. def func(url):
  10. s = "这是 {} 页!".format(url)
  11. 返回字节(s, 编码="utf8")
  12. 正确:
  13. #等待连接
  14. conn,添加 = sk.accept()
  15. data = conn.recv(8096) # 接收客户端发来的消息
  16. #从数据中获取路径
  17. data = str(data,encoding="utf8") #将接收到的字节类型数据转换为字符串
  18. # 分割为 \r\n
  19. data1 = data.split("\r\n")[0]
  20. url = data1.split()[1] #url是我们从浏览器发送的消息中分离出来的访问路径
  21.   conn.send(b'HTTP/1.1 200 OK\r\n\r\n') #因为必须遵循HTTP协议,所以回复消息也必须添加状态行
  22. #根据不同路径返回不同内容,response为具体响应体
  23.     if url == "/index/":  
  24.         响应= func(url)  
  25.     elif url == "/home/":  
  26.         响应= func(url)  
  27.     其他:  
  28.         回复 = b“404 未找到!”
  29.   
  30.     conn.send(响应)  
  31.     conn.close()  

def func(url):
s = "​​这是 {} 页!".format(url)
返回字节(s,编码="​​utf8")

 

根据不同的路径返回不同的内容--函数进阶版本

看起来上面的代码写了一个函数,那肯定可以写多个函数,不同的路径对应执行不同的函数得到结果,但是我们要一个判断路径,是不是很麻烦?我们有简单的办法来解决。

  1. “””
  2. 根据URL中不同的路径返回不同的内容--函数进阶版本
  3. """  
  4. 进口插座
  5. sk = socket.socket()
  6. sk.bind(("127.0.0.1", 8080)) #绑定IP和端口
  7. sk.listen() # 听力
  8. #将返回的内容部分封装成不同的函数
  9. def索引(url):
  10. s = "这是{}第 XX 页!".format(url)
  11. 返回字节(s, 编码="utf8")
  12. def home(url):
  13. s = "这是 {} 页..!".format(url)
  14. 返回字节(s, 编码="utf8")
  15. #定义一个url和实际要执行的函数的对应关系
  16. 列表1 = [
  17. "/索引/",索引),
  18. “/家/”,家),
  19. ]
  20. 同时正确:
  21. #等待连接
  22. conn,添加 = sk.accept()
  23. data = conn.recv(8096) # 接收客户端发来的消息
  24. #从数据中获取路径
  25. data = str(data,encoding="utf8") #将接收到的字节类型数据转换为字符串
  26. # 分割为 \r\n
  27. data1 = data.split("\r\n")[0]
  28. url = data1.split()[1] #url是我们从浏览器发送的消息中分离出来的访问路径
  29.   conn.send(b'HTTP/1.1 200 OK\r\n\r\n') #因为必须遵循HTTP协议,所以回复消息也必须添加状态行
  30. #根据不同路径返回不同内容
  31. func = None #定义一个变量,保存要执行的函数的名称
  32. 对于列表 1 中的项目
  33. if item[0] == url:
  34.                                                                                                                     , ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  35.       断 
  36. 如果功能:
  37.     响应 = func(url)  
  38. 其他:
  39.     回复= b“404未找到!”
  40. #返回具体回复信息
  41. conn.send(响应)
  42. conn.close()

分析:

1)定义多个函数,将提取的URL后面的访问目录传入函数中,并执行函数。
2)定义一个列表,其中有很多元组对应字符串和函数名
3)定义一个变量为None,循环遍历列表元素,判断该元素的第一个字符元素是否取自url To访问文件时,该变量被重新赋值给该元素的第二个字符元素,即该变量等于4和一个定义的函数名。
4)如果func为true且访问url中匹配成功,则执行该函数,并使用返回数据变量接收函数返回值,否则请求返回的变量将是404未找到。
5)然后将请求返回的数据发送给浏览器。这样就实现了一个框架。

返回特定HTML文件

完美解决不同URL返回不同内容的问题。但我不想只返回一些字符串。我想向浏览器返回完整的 HTML 内容。我应该怎么办?

没问题,无论内容是什么,最终都会转换成字节数据发送出去。我们可以打开HTML文件,读出其中的二进制数据,然后将其发送到浏览器。

  1. “””
  2. 根据URL中不同路径返回不同内容--高级版功能
  3. 返回独立HTML页面
  4. “””
  5. 进口插座
  6. sk = socket.socket()
  7. sk.bind(("127.0.0.1", 8080)) #绑定IP和端口
  8. sk.listen() # 听力
  9. #将返回的内容部分封装成不同的函数
  10. def索引(url):
  11. #阅读index.html页面内容
  12. 打开("index.html", "r", 编码="utf8") 作为 f:
  13. s = www.sychzs.cn()
  14. #返回字节数据
  15. 返回字节(s, 编码="utf8")
  16. def home(url):
  17. 打开("home.html", "r", 编码="utf8") 作为 f:
  18. s = www.sychzs.cn()
  19. 返回字节(s, 编码="utf8")
  20. #定义一个url和实际要执行的函数的对应关系
  21. 列表1 = [
  22. "/索引/",索引),
  23. “/家/”,家),
  24. ]
  25. 正确:
  26. #等待连接
  27. conn,添加 = sk.accept()
  28. data = conn.recv(8096) # 接收客户端发来的消息
  29. #从数据中获取路径
  30. data = str(data,encoding="utf8") #将接收到的字节类型数据转换为字符串
  31. # 分割为 \r\n
  32. data1 = data.split("\r\n")[0]
  33. url = data1.split()[1] #url是我们从浏览器发送的消息中分离出来的访问路径
  34.   conn.send(b'HTTP/1.1 200 OK\r\n\r\n') #因为必须遵循HTTP协议,所以回复消息也必须添加状态行
  35. #根据不同路径返回不同内容
  36. func = None #定义一个变量,保存要执行的函数的名称
  37. 对于列表 1 中的项目
  38. if item[0] == url:
  39.                                                                                                                          ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  40. 如果功能:
  41.     响应 = func(url)  
  42. 其他:
  43.     回复= b“404未找到!”
  44. #返回具体回复信息
  45. conn.send(响应)
  46. conn.close()

"​​en">

<元字符集="​​UTF-8">"​​x-ua-兼容"内容="​​IE=边缘" >
<元名称="​​视口"内容="​​宽度=设备宽度,初始比例=1">
索引


这是索引页面
index.html

"​​en">

<元字符集="​​UTF-8">
"​​x-ua-兼容"内容="​​IE=边缘" >
<元名称="​​视口"内容="​​宽度=设备宽度,初始比例=1">
索引


这是主页
home.html

1)在执行上一个请求的函数中,函数的返回值由字符串改为返回html对应的文件内容。
2)实现方法是在函数中读取文件内容,然后改变前面函数中定义的字符串,返回读取的文件数据。
3)下面的程序与上面相同,这样可以根据不同的URL执行不同的功能,并向浏览器返回不同的数据:
  2)定义一个包含多个字符的列表列表中字符串和函数名对应的元组
  3)定义一个变量为None,循环遍历列表元素,判断该元素的第一个字符元素是否是从列表中取出的access文件网址。如果是,则将变量重新赋值给该元素的第二个字元素,即该变量等于4和一个定义的函数名。
  4)如果func为true且访问url中匹配成功,则执行该函数,并使用返回数据变量接收函数返回值,否则请求返回的变量将是404 not成立。
  5)然后将请求返回的数据发送到浏览器。这样就实现了一个框架。

让网页变得动态

这个网页可以显示,但都是静态的。页面内容不会改变。我想要的是一个动态的网站。

没问题,我也有办法解决。我选择使用字符串替换来实现这个需求。(这里使用时间戳来模拟动态的数据)

  1. """ 
  2. 根据URL中不同的路径返回不同的内容--函数进阶版 
  3. 返回独立的HTML页面 
  4. """  
  5.   
  6. import socket  
  7.   
  8. sk = socket.socket()  
  9. sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口  
  10. sk.listen()  # 监听  
  11.   
  12.   
  13. # 将返回不同的内容部分封装成不同的函数  
  14. def index(url):  
  15.     # 读取index.html页面的内容  
  16.     with open("index.html", "r", encoding="utf8") as f:  
  17.         s = www.sychzs.cn()  
  18.     # 返回字节数据  
  19.     return bytes(s, encoding="utf8")  
  20.   
  21.   
  22. def home(url):  
  23.     with open("home.html", "r", encoding="utf8") as f:  
  24.         s = www.sychzs.cn()  
  25.     return bytes(s, encoding="utf8")  
  26.   
  27.   
  28. def timer(url):  
  29.     import time  
  30.     with open("time.html", "r", encoding="utf8") as f:  
  31.         s = www.sychzs.cn()  
  32.         s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S"))  
  33.     return bytes(s, encoding="utf8")  
  34.   
  35.   
  36. # 定义一个url和实际要执行的函数的对应关系  
  37. list1 = [  
  38.     ("/index/", index),  
  39.     ("/home/", home),  
  40.     ("/time/", timer),  
  41. ]  
  42.   
  43. while True:  
  44.     # 等待连接  
  45.     conn, add = sk.accept()  
  46.     data = conn.recv(8096)  # 接收客户端发来的消息  
  47.     # 从data中取到路径  
  48.     data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串  
  49.     # 按\r\n分割  
  50.     data1 = data.split("\r\n")[0]  
  51.     url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径  
  52.     conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行  
  53.     # 根据不同的路径返回不同内容  
  54.     func = None  # 定义一个保存将要执行的函数名的变量  
  55.     for item in list1:  
  56.         if item[0] == url:  
  57.             func = item[1]  
  58.             break  
  59.     if func:  
  60.         response = func(url)  
  61.     else:  
  62.         response = b"404 not found!"  
  63.   
  64.     # 返回具体的响应消息  
  65.     conn.send(response)  
  66.     conn.close()  

"en">

"UTF-8">
"x-ua-compatible" content="IE=edge">
"viewport" content="width=device-width, initial-scale=1">
time


当前时间是:@@time@@
View Code
当前时间是:@@time@@
在代码中将文件读取出来,然后字符串替换成当前的时间,然后作为函数返回值编码发送给访问这个地址的请求。实现网页中数据不固定,用数据渲染显示页面。

 

回到顶部

服务器程序和应用程序

对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。

服务器程序负责对socket服务端进行封装,并在请求到来时,对请求的各种数据进行整理。

应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、www.sychzs.cn 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。

 

这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。

这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。

常用的WSGI服务器有uWSGI、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

 

wsgiref

我们利用wsgiref模块来替换我们自己写的web框架的socket server部分:

  1. """  
  2. 根据URL中不同的路径返回不同的内容--函数进阶版  
  3. 返回HTML页面  
  4. 让网页动态起来  
  5. wsgiref模块版  
  6. """   
  7.      
  8. from wsgiref.simple_server import make_server   
  9.      
  10.      
  11. # 将返回不同的内容部分封装成函数   
  12. def index(url):   
  13.     # 读取index.html页面的内容   
  14.     with open("index.html", "r", encoding="utf8") as f:   
  15.         s = www.sychzs.cn()   
  16.     # 返回字节数据   
  17.     return bytes(s, encoding="utf8")   
  18.      
  19.      
  20. def home(url):   
  21.     with open("home.html", "r", encoding="utf8") as f:   
  22.         s = www.sychzs.cn()   
  23.     return bytes(s, encoding="utf8")   
  24.      
  25.      
  26. def timer(url):   
  27.     import time   
  28.     with open("time.html", "r", encoding="utf8") as f:   
  29.         s = www.sychzs.cn()   
  30.         s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S"))   
  31.     return bytes(s, encoding="utf8")   
  32.      
  33.      
  34. # 定义一个url和实际要执行的函数的对应关系   
  35. list1 = [   
  36.     ("/index/", index),   
  37.     ("/home/", home),   
  38.     ("/time/", timer),   
  39. ]   
  40.      
  41.      
  42. def run_server(environ, start_response):   
  43.     start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息   
  44.     url = environ['PATH_INFO']  # 取到用户输入的url   
  45.     func = None   
  46.     for i in list1:   
  47.         if i[0] == url:   
  48.             func = i[1]   
  49.             break   
  50.     if func:   
  51.         response = func(url)   
  52.     else:   
  53.         response = b"404 not found!"   
  54.     return [response, ]   
  55.      
  56.      
  57. if __name__ == '__main__':   
  58.     httpd = make_server('127.0.0.1', 8090, run_server)   
  59.     print("我在8090等你哦...")   
  60.     httpd.serve_forever()  

{
'ALLUSERSPROFILE': 'C:\\ProgramData',
'APPDATA': 'C:\\Users\\Administrator\\AppData\\Roaming',
'COMMONPROGRAMFILES': 'C:\\Program Files (x86)\\Common Files',
'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files',
'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files',
'COMPUTERNAME': 'PC-20190328RVNA',
'COMSPEC': 'C:\\Windows\\system32\\cmd.exe',
'FP_NO_HOST_CHECK': 'NO',
'HOMEDRIVE': 'C:',
'HOMEPATH': '\\Users\\Administrator',
'LOCALAPPDATA': 'C:\\Users\\Administrator\\AppData\\Local',
'LOGONSERVER': '\\\\PC-20190328RVNA',
'NUMBER_OF_PROCESSORS': '4',
'OS': 'Windows_NT',
'PATH': 'C:\\mcw\\venv\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\软件安装\\Git\\cmd;C:\\mysql\\mysql-5.6.44-winx64\\bin;C:\\python3\\Scripts\\;C:\\python3\\',
'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC',
'PROCESSOR_ARCHITECTURE': 'x86',
'PROCESSOR_ARCHITEW6432': 'AMD64',
'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 58 Stepping 9, GenuineIntel',
'PROCESSOR_LEVEL': '6',
'PROCESSOR_REVISION': '3a09',
'PROGRAMDATA': 'C:\\ProgramData',
'PROGRAMFILES': 'C:\\Program Files (x86)',
'PROGRAMFILES(X86)': 'C:\\Program Files (x86)',
'PROGRAMW6432': 'C:\\Program Files',
'PROMPT': '(venv) $P$G',
'PSMODULEPATH': 'C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
'PUBLIC': 'C:\\Users\\Public',
'PYCHARM_HOSTED': '1',
'PYCHARM_MATPLOTLIB_PORT': '59585',
'PYTHONIOENCODING': 'UTF-8',
'PYTHONPATH': 'C:\\mcw;C:\\软件安装\\PyCharm 2018.3.5\\helpers\\pycharm_matplotlib_backend',
'PYTHONUNBUFFERED': '1',
'SESSIONNAME': 'Console',
'SYSTEMDRIVE': 'C:',
'SYSTEMROOT': 'C:\\Windows',
'TEMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp',
'TMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp',
'USERDOMAIN': 'PC-20190328RVNA',
'USERNAME': 'Administrator',
'USERPROFILE': 'C:\\Users\\Administrator',
'VIRTUAL_ENV': 'C:\\mcw\\venv',
'WINDIR': 'C:\\Windows',
'WINDOWS_TRACING_FLAGS': '3',
'WINDOWS_TRACING_LOGFILE': 'C:\\BVTBin\\Tests\\installpackage\\csilogfile.log',
'_OLD_VIRTUAL_PATH': 'C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\杞\ue219欢瀹夎\ue5ca\\Git\\cmd;C:\\mysql\\mysql-5.6.44-winx64\\bin;C:\\python3\\Scripts\\;C:\\python3\\',
'_OLD_VIRTUAL_PROMPT': '$P$G',
'SERVER_NAME': 'PC-20190328RVNA',
'GATEWAY_INTERFACE': 'CGI/1.1',
'SERVER_PORT': '8090',
'REMOTE_HOST': '',
'CONTENT_LENGTH': '',
'SCRIPT_NAME': '',
'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'WSGIServer/0.2',
'REQUEST_METHOD': 'GET',
'PATH_INFO': '/time/',
'QUERY_STRING': '',
'REMOTE_ADDR': '127.0.0.1',
'CONTENT_TYPE': 'text/plain',
'HTTP_HOST': '127.0.0.1:8090',
'HTTP_CONNECTION': 'keep-alive',
'HTTP_CACHE_CONTROL': 'max-age=0',
'HTTP_UPGRADE_INSECURE_REQUESTS': '1',
'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 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',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br',
'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9',
'wsgi.input': < _io.BufferedReader name = 564 > ,
'wsgi.errors': < _io.TextIOWrapper name = ''
mode = 'w'
encoding = 'UTF-8' > ,
'wsgi.version': (1, 0),
'www.sychzs.cn_once': False,
'wsgi.url_scheme': 'http',
'wsgi.multithread': True,
'wsgi.multiprocess': False,
'wsgi.file_wrapper': < class 'wsgiref.util.FileWrapper' >
} <
bound method BaseHandler.start_response of < wsgiref.simple_server.ServerHandler object at 0x02A06950 >>
127.0 .0 .1 - -[11 / Jun / 2019 19: 12: 41]
"GET /time/ HTTP/1.1"
200 301 {
'ALLUSERSPROFILE': 'C:\\ProgramData',
'APPDATA': 'C:\\Users\\Administrator\\AppData\\Roaming',
'COMMONPROGRAMFILES': 'C:\\Program Files (x86)\\Common Files',
'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files',
'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files',
'COMPUTERNAME': 'PC-20190328RVNA',
'COMSPEC': 'C:\\Windows\\system32\\cmd.exe',
'FP_NO_HOST_CHECK': 'NO',
'HOMEDRIVE': 'C:',
'HOMEPATH': '\\Users\\Administrator',
'LOCALAPPDATA': 'C:\\Users\\Administrator\\AppData\\Local',
'LOGONSERVER': '\\\\PC-20190328RVNA',
'NUMBER_OF_PROCESSORS': '4',
'OS': 'Windows_NT',
'PATH': 'C:\\mcw\\venv\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\软件安装\\Git\\cmd;C:\\mysql\\mysql-5.6.44-winx64\\bin;C:\\python3\\Scripts\\;C:\\python3\\',
'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC',
'PROCESSOR_ARCHITECTURE': 'x86',
'PROCESSOR_ARCHITEW6432': 'AMD64',
'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 58 Stepping 9, GenuineIntel',
'PROCESSOR_LEVEL': '6',
'PROCESSOR_REVISION': '3a09',
'PROGRAMDATA': 'C:\\ProgramData',
'PROGRAMFILES': 'C:\\Program Files (x86)',
'PROGRAMFILES(X86)': 'C:\\Program Files (x86)',
'PROGRAMW6432': 'C:\\Program Files',
'PROMPT': '(venv) $P$G',
'PSMODULEPATH': 'C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
'PUBLIC': 'C:\\Users\\Public',
'PYCHARM_HOSTED': '1',
'PYCHARM_MATPLOTLIB_PORT': '59585',
'PYTHONIOENCODING': 'UTF-8',
'PYTHONPATH': 'C:\\mcw;C:\\软件安装\\PyCharm 2018.3.5\\helpers\\pycharm_matplotlib_backend',
'PYTHONUNBUFFERED': '1',
'SESSIONNAME': 'Console',
'SYSTEMDRIVE': 'C:',
'SYSTEMROOT': 'C:\\Windows',
'TEMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp',
'TMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp',
'USERDOMAIN': 'PC-20190328RVNA',
'USERNAME': 'Administrator',
'USERPROFILE': 'C:\\Users\\Administrator',
'VIRTUAL_ENV': 'C:\\mcw\\venv',
'WINDIR': 'C:\\Windows',
'WINDOWS_TRACING_FLAGS': '3',
'WINDOWS_TRACING_LOGFILE': 'C:\\BVTBin\\Tests\\installpackage\\csilogfile.log',
'_OLD_VIRTUAL_PATH': 'C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\杞\ue219欢瀹夎\ue5ca\\Git\\cmd;C:\\mysql\\mysql-5.6.44-winx64\\bin;C:\\python3\\Scripts\\;C:\\python3\\',
'_OLD_VIRTUAL_PROMPT': '$P$G',
'SERVER_NAME': 'PC-20190328RVNA',
'GATEWAY_INTERFACE': 'CGI/1.1',
'SERVER_PORT': '8090',
'REMOTE_HOST': '',
'CONTENT_LENGTH': '',
'SCRIPT_NAME': '',
'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'WSGIServer/0.2',
'REQUEST_METHOD': 'GET',
'PATH_INFO': '/favicon.ico',
'QUERY_STRING': '',
'REMOTE_ADDR': '127.0.0.1',
'CONTENT_TYPE': 'text/plain',
'HTTP_HOST': '127.0.0.1:8090',
'HTTP_CONNECTION': 'keep-alive',
'HTTP_PRAGMA': 'no-cache',
'HTTP_CACHE_CONTROL': 'no-cache',
'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
'HTTP_ACCEPT': 'image/webp,image/apng,image/*,*/*;q=0.8',
'HTTP_REFERER': 'http://127.0.0.1:8090/time/',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br',
'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9',
'wsgi.input': < _io.BufferedReader name = 564 > ,
'wsgi.errors': < _io.TextIOWrapper name = ''
mode = 'w'
encoding = 'UTF-8' > ,
'wsgi.version': (1, 0),
'www.sychzs.cn_once': False,
'wsgi.url_scheme': 'http',
'wsgi.multithread': True,
'wsgi.multiprocess': False,
'wsgi.file_wrapper': < class 'wsgiref.util.FileWrapper' >
}
打印environ并格式化后显示所有变量

获取环境变量一个键:environ['PATH_INFO']

键的值是后面的值,就是url中获取到的值,: 'PATH_INFO': '/time/',

'PATH': 'C:\\mcw\\venv\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\软件安装\\Git\\cmd;C:\\mysql\\mysql-5.6.44-winx64\\bin;C:\\python3\\Scripts\\;C:\\python3\\',

start_response是个对象:>

 

from wsgiref.simple_server import make_server
def run_server(environ, start_response): #2)定义执行函数,传参environ, start_response
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 4) 设置HTTP响应的状态码和头信息start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) 
url = environ['PATH_INFO']  #3)取到用户输入的url environ['PATH_INFO']
if url=='/home/':
response=("response:"+url).encode('utf-8')
else:
response = b"404 not found!" #)url满足条件返回内容定义
return [response, ] #6)执行函数返回列表,列表一个元素是返回的内容
if __name__ == '__main__':
httpd = make_server('127.0.0.1', 8090, run_server) #1)make_server 做服务传ip端口和执行函数
httpd.serve_forever()  #启动这个服务

用wsgiref代替服务端socket创建简易web框架:

1)make_server 做服务传ip端口和执行函数
2)定义执行函数,传参environ, start_response
3)取到用户输入的url environ['PATH_INFO']
4) 设置HTTP响应的状态码和头信息start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) 
5)url满足条件返回内容定义
6)执行函数返回列表,列表一个元素是返回的内容

7)启动这个服务

jinja2

上面的代码实现了一个简单的动态,我完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。 这个过程就相当于HTML模板渲染数据。 本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。 我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具: jinja2

下载jinja2:

pip install jinja2

"zh-CN">

"UTF-8">
"x-ua-compatible" content="IE=edge">
"viewport" content="width=device-width, initial-scale=1">
Title


姓名:{{name}}

爱好:

    {% for hobby in hobby_list %}
  • {{hobby}}
  • {% endfor %}
index2.html

使用jinja2渲染index2.html文件:

  1. from wsgiref.simple_server import make_server  
  2. from jinja2 import Template  
  3.   
  4.   
  5. def index(url):  
  6.     # 读取HTML文件内容  
  7.     with open("index2.html", "r", encoding="utf8") as f:  
  8.         data = www.sychzs.cn()  
  9.         template = Template(data)   # 生成模板文件  
  10.         ret = template.render({'name': '小郭吹雪', 'hobby_list': ['敲代码', '今日头条', '睡觉']} # 把数据填充到模板中  
  11.     return bytes(ret, encoding="utf8")  
  12.   
  13.   
  14. def home(url):  
  15.     with open("home.html", "r", encoding="utf8") as f:  
  16.         s = www.sychzs.cn()  
  17.     return bytes(s, encoding="utf8")  
  18.   
  19.   
  20. # 定义一个url和实际要执行的函数的对应关系  
  21. list1 = [  
  22.     ("/index/", index),  
  23.     ("/home/", home),  
  24. ]  
  25.   
  26.   
  27. def run_server(environ, start_response):  
  28.     start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息  
  29.     url = environ['PATH_INFO']  # 取到用户输入的url  
  30.     func = None  
  31.     for i in list1:  
  32.         if i[0] == url:  
  33.             func = i[1]  
  34.             break  
  35.     if func:  
  36.         response = func(url)  
  37.     else:  
  38.         response = b"404 not found!"  
  39.     return [response, ]  
  40.   
  41.   
  42. if __name__ == '__main__':  
  43.     httpd = make_server('127.0.0.1', 8090, run_server)  
  44.     print("我在8090等你哦...")  
  45.     httpd.serve_forever()  
jinja2使用方法;

1)从jinja2导入模板类
2)实例化模板类,传参为带特别语法的文件。
3)对象.render(字典),把数据填充到模板中
4)支持{{name}}双括号中变量替换为字典键的值,for循环创建语句。
  {'name': '小郭吹雪', 'hobby_list': ['敲代码', '今日头条', '睡觉']

  双花中代表变量,字典的键:

姓名:{{name}}


  上下花百分。上for循环字典键中列表,下endfor。中间是对for循环的每个变量生成html。
  {% for hobby in hobby_list %}
  
  • {{hobby}}

  •   {% endfor %}

     

    现在的数据是我们自己手写的,那可不可以从数据库中查询数据,来填充页面呢?

    使用pymysql连接数据库:

    conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select name, age, department_id from userinfo")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()

    创建一个测试的user表:

    CREATE TABLE user(
    id int auto_increment PRIMARY KEY,
    name CHAR(10) NOT NULL,
    hobby CHAR(20) NOT NULL
    )engine=innodb DEFAULT charset=UTF8;

    模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。

    回到顶部

    Django

    Django官网下载页面

    安装(安装最新LTS版):

    pip3 install django==1.11.20

    指定安装源(清华源):

    pip3 install django==1.11.21 -i https://www.sychzs.cn/simple

    pycharm安装Django,指定版本

     shift右击 在当前目录打开cmd

    创建一个django项目:

    下面的命令创建了一个名为"mysite"的Django 项目:

    django-admin startproject mysite

    目录介绍:

    mysite/
    ├── www.sychzs.cn  # 管理文件
    └── mysite  # 项目目录
    ├── __init__.py
    ├── www.sychzs.cn  # 配置
    ├── www.sychzs.cn  # 路由 --> URL和函数的对应关系
    └── www.sychzs.cn  # runserver命令就使用wsgiref模块做简单的web server

    pycharm创建,社区版不支持创建django项目。

    file->new project->Django

    location项目路径,名称。

    解释器

    虚拟环境:能隔离开各个项目的环境

    不写不自动生成这个目录

     

     修改配置:

     

     

     

    运行Django项目:

    默认端口8000么?

     

    python www.sychzs.cn runserver 127.0.0.1:8000

    1.命令行
    切换到项目的根目录下  www.sychzs.cn
    python36 www.sychzs.cn runserver # http://127.0.0.1:8000/
    
    python36 www.sychzs.cn runserver 80   #指定端口启动  在80端口启动
    python36 www.sychzs.cn runserver 0.0.0.0:80  #0.0.0.0:80 其它主机可访问,外部主机可访问

    直接点击启动关闭

     

    python36 www.sychzs.cn runserver 0.0.0.0:80#并且settings设置为‘*’,允许所有主机访问

     

    terminate是项目终止,disconnect是断开连接,项目不终止

    命令行开启的可以crtl + c终止

    disconect点击之后,要停止项目。可以在资源管理器中杀掉进程

    多了个文件:

     如果启动时报错哪个文件的问题,看看是不是启动错了,启动的不是Django项目而是某个文件:

     

     

    模板文件配置:

    TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, "template")],  # template文件夹位置
    'APP_DIRS': True,
    'OPTIONS': {
    'context_processors': [
    'django.template.context_processors.debug',
    'django.template.context_processors.request',
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
    ],
    },
    },
    ]

    静态文件配置:

    STATIC_URL = '/static/'  # HTML中使用的静态文件夹前缀
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),  # 静态文件存放位置
    ]

    看不明白?有图有真相:

    刚开始学习时可在配置文件中暂时禁用csrf中间件,方便表单提交测试。

    MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    回到顶部

    Django基础必备三件套:

    from django.shortcuts import HttpResponse, render, redirect

    HttpResponse

    内部传入一个字符串参数,返回给浏览器。

    例如:

    def index(request):
    # 业务逻辑代码
    return HttpResponse("OK")

    创建一个页面

    from django.contrib import admin
    from django.urls import path
    from django.shortcuts import HttpResponse,render
    def index(request):
    return HttpResponse('index')
    urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', index),
    ]
    View Code

     

    render

    除request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数。

    将数据填充进模板文件,最后把结果返回给浏览器。(类似于我们上面用到的jinja2)

    例如:

    def index(request):
    # 业务逻辑代码
    return render(request, "index.html", {"name": "alex", "hobby": ["烫头", "泡吧"]})

    from django.contrib import admin
    from django.urls import path
    from django.shortcuts import HttpResponse,render
    def index(request):
    # return HttpResponse('index')
    return render(request,'index.html')
    urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', index),
    ]
    View Code

     

    redirect

    接受一个URL参数,表示跳转到指定的URL。

    例如:

    def index(request):
    # 业务逻辑代码
    return redirect("/home/")
    回到顶部

    重定向是怎么回事?

    回到顶部

    启动Django报错:

    Django 启动时报错 UnicodeEncodeError ...

    报这个错误通常是因为计算机名为中文,改成英文的计算机名重启下电脑就可以了。

     

     

     

     

    相关文章

    最新资讯