热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

框架里面的标签采集不到怎么办_Django基础一之web框架的本质he。

web框架的本质及自定义web框架我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端ÿ

web框架的本质及自定义web框架

  我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,基于请求做出响应,客户都先请求,服务端做出对应的响应,按照http协议的请求协议发送请求,服务端按照http协议的响应协议来响应请求,这样的网络通信,我们就可以自己实现Web框架了。

  通过对socket的学习,我们知道网络通信,我们完全可以自己写了,因为socket就是做网络通信用的,下面我们就基于socket来自己实现一个web框架,写一个web服务端,让浏览器来请求,并通过自己的服务端把页面返回给浏览器,浏览器渲染出我们想要的效果。在后面的学习中,大家提前准备一些文件:

html文件内容如下,名称为: 

姑娘,你好,我是Jaden,请问约吗?嘻嘻~~

css文件内容如下,名称为:

h1{background-color: green;color: white;
}

js文件内容如下,名称为:

再准备一个图片,名称为,再准备一个ico文件,名称为,其实就是个图片文件,微信官网打开之后,在浏览器最上面能够看到50c424140e4fb6bd0a4e139b2da2088f.png,把它保存下来

上面的文件都准备好之后,你用pycharm新建一个项目,把文件都放到一个文件夹里面去,留着备用,像下面这个样子:5639c2f9c09828fef1c50cfe3fdcb458.png

然后开始写我们的web框架,我们分这么几步来写:

一、简单的web框架

创建一个python文件,内容如下,名称为:

import socket
sk = ()
(('',8001))
()
conn,addr = ()
from_b_msg = (1024)
str_msg = ('utf-8')
#socket是应用层和传输层之间的抽象层,每次都有协议,协议就是消息格式,那么传输层的消息格式我们不用管,因为socket帮我们搞定了,但是应用层的协议还是需要咱们自己遵守的,所以再给浏览器发送消息的时候,如果没有按照应用层的消息格式来写,那么你返回给浏览器的信息,浏览器是没法识别的。而应用层的协议就是我们的HTTP协议,所以我们按照HTTP协议规定的消息格式来给浏览器返回消息就没有问题了,关于HTTP我们会细说,首先看一下直接写(b'hello')的效果,然后运行代码,通过浏览器来访问一下,然后再看这一句(b'HTTP/1.1 200 ok \r\n\r\nhello')的效果
#下面这句就是按照http协议来写的
# (b'HTTP/1.1 200 ok \r\n\r\nhello')
#上面这句还可以分成下面两句来写
(b'HTTP/1.1 200 ok \r\n\r\n')
(b'hello')

我们来浏览器上看一下浏览器发送的请求

c066c944570568e5c702afcd71abcf4d.png

目前我们还没有写如何返回一个html文件给浏览器,所以这里暂时不用管它,那么我们点开这个看看:

90151a3e7869d75e950bd92ae7ac83f3.png

我们在python文件中打印一下浏览器发送过来的请求信息是啥:

2188ff1cc0cb9d794fdfbb0a4274ae4f.png

重启我们的代码,然后在网址中输入这个:

e73bd1fe9bcae9d3dfe23851f74567b8.png

再重启我们的代码,然后在网址中输入这个:

df56d7ee68b350cd8c40a258f5378710.png

浏览器发过来一堆的消息,我们给浏览器回复(响应)信息的时候,也要按照一个消息格式来写,这些都是http协议规定的,那么我们就来学习一下http协议,然后继续完善我们的web框架:

HTTP协议:

二、返回HTML文件的web框架

首先写一个html文件,内容如下,名称为:

姑娘,你好,我是Jaden,请问约吗?嘻嘻~~

准备我们的python代码,服务端程序,文件内容如下,文件名称为:

import socket
sk = ()
(('',8001))
()
conn,addr = ()
from_b_msg = (1024)
str_msg = ('utf-8')
print('浏览器请求信息:',str_msg)# (b'HTTP/1.1 200 ok \r\ncontent-type:text/html;charset=utf-8;\r\n')
(b'HTTP/1.1 200 ok \r\n\r\n')with open('','rb') as f:f_data = ()
(f_data)

页面上输入网址看效果,css和js代码的效果也有,very good:

285941a402a0bf471f01d173e4263f1f.png

但是我们知道,我们的css和js基本都是写在本地的文件里面的啊,而且我们的图片基本也是我们自己本地的啊,怎么办,我们将上面我们提前准备好的js和css还有那个.ico结尾的图片文件都准备好,来我们在来一个升级版的web框架,其实css、js、图片等文件都叫做网站的静态文件。

首先我们先看一个效果,如果我们直接将我们写好的css和js还有.ico和图片文件插入到我们的html页面里面,就是下面这个html文件

名称为,内容如下:

姑娘,你好,我是Jaden,请问约吗?嘻嘻~~

同样使用我们之前的python程序,来看效果:

755a73bc0802650f72ca5fed794f582e.png

发现js和css的效果都没有出来,并且我们看一下浏览器调试窗口的那个network

6faa785bb47c4554194a87da9a14744c.png

在下来我们在network里面点击那个文件,看看请求是什么:

f6ab844e1a4b7b1c0d66ab3efa47b5ec.png

还有就是当我们直接在浏览器上保存某个页面的时候,随便一个页面,我们到页面上点击右键另存为,然后存到本地的一个目录下,你会发现这个页面的html、css、js、图片等文件都跟着保存下来了,我保存了一下博客园首页的页面,看,是一个文件夹和一个html文件:

a8d73d86b709743b37b86b031aae2462.png

我们点开博客园那个文件夹看看里面都有什么:

b12549b837ffb8af12a04c1030353aad.png

发现js、css还有图片什么的都被保存了下来,说明什么,说明这些文件本身就存在浏览器上了,哦,原来就是将html页面需要的css、js、图片等文件也发送给浏览器就可以了,并且这些静态文件都是浏览器单独过来请求的,其实和标签的属性有有关系,css文件是link标签的href属性:,js文件是script标签的src属性:,图片文件是img标签的src属性: ,那个.ico文件是link标签的属性:,其实这些属性都会在页面加载的时候,单独到自己对应的属性值里面取请求对应的文件数据,而且我们如果在值里面写的都是自己本地的路径,那么都会来自己的本地路径来找,如果我们写的是相对路径,就会到我们自己的网址+文件名称,这个路径来找它需要的文件,所以我们只需要将这些请求做一些响应,将对应的文件数据相应给浏览器就可以了!并且我们通过前面的查看,能够发现,浏览器url的请求路径我们知道是什么,静态文件不是也这样请求的吗,好,我们针对不同的路径给它返回不同的文件,c6e0951fc71194d0761dd845e5ea8db2.png非常好!我们来尝试一下!

三、返回静态文件的高级web框架

还是用第二个web框架里面的那个html文件,我们只需要写一些我们的服务端程序就可以了,同样是文件,内容如下:

import socketsk = ()
(('',8001))
()#首先浏览器相当于给我们发送了多个请求,一个是请求我们的html文件,而我们的html文件里面的引入文件的标签又给我们这个网站发送了请求静态文件的请求,所以我们要将建立连接的过程循环起来,才能接受多个请求,没毛病while 1:conn,addr = ()# while 1:from_b_msg = (1024)str_msg = ('utf-8')#通过http协议我们知道,浏览器请求的时候,有一个请求内容的路径,通过对请求信息的分析,这个路径我们在请求的所有请求信息中可以提炼出来,下面的path就是我们提炼出来的路径path = ('\r\n')[0].split('')[1]print('path>>>',path)(b'HTTP/1.1 200 ok \r\n\r\n')#由于整个页面需要html、css、js、图片等一系列的文件,所以我们都需要给人家浏览器发送过去,浏览器才能有这些文件,才能很好的渲染你的页面#根据不同的路径来返回响应的内容if path == '/': #返回html文件print(from_b_msg)with open('','rb') as f:# with open('Python开发.html','rb') as f:data = ()(data)()elif path == '/': #返回图片with open('','rb') as f:pic_data = ()# (b'HTTP/1.1 200 ok \r\n\r\n') (pic_data)()elif path == '/': #返回css文件with open('','rb') as f:css_data = ()(css_data)()elif path == '/':#返回页面的ico图标with open('','rb') as f:ico_data = ()(ico_data)()elif path == '/': #返回js文件with open('','rb') as f:js_data = ()(js_data)()#注意:上面每一个请求处理完之后,都有一个()是因为,HTTP协议是短链接的,一次请求对应一次响应,这个请求就结束了,所以我们需要写上close,不然浏览器自己断了,你自己写的服务端没有断,就会出问题。

运行起来我们的py文件,然后在浏览器访问一下我们的服务端,看效果:

e04d324cae32a32584db67c1e06f3f3c.png

完全搞定了,自己通过socket已经完全搞定了web项目。

函数版高级web框架

html文件和其他的静态文件还是我们上面使用的。

python代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2019/2/17 14:06
# @Author : wuchao
# @Site :
# @File :
# @Software: PyCharmimport socketsk = ()
(('',8001))
()#处理页面请求的函数def func1(conn):with open('', 'rb') as f:# with open('Python开发.html','rb') as f:data = ()(data)()#处理页面img标签src属性值是本地路径的时候的请求def func2(conn):with open('', 'rb') as f:pic_data = ()# (b'HTTP/1.1 200 ok \r\n\r\n') (pic_data)()
#处理页面link( )标签href属性值是本地路径的时候的请求def func3(conn):with open('', 'rb') as f:css_data = ()(css_data)()#处理页面link()标签href属性值是本地路径的时候的请求def func4(conn):with open('', 'rb') as f:ico_data = ()(ico_data)()#处理页面script()标签src属性值是本地路径的时候的请求def func5(conn):with open('', 'rb') as f:js_data = ()(js_data)()while 1:conn,addr = ()# while 1:from_b_msg = (1024)str_msg = ('utf-8')path = ('\r\n')[0].split('')[1]print('path>>>',path)(b'HTTP/1.1 200 ok \r\n\r\n')print(from_b_msg)if path == '/':func1(conn)elif path == '/':func2(conn)elif path == '/':func3(conn)elif path == '/':func4(conn)elif path == '/':func5(conn)

更高级版(多线程版)web框架

应用上我们并发编程的内容,反正html文件和静态文件都直接给浏览器,那大家就一块并发处理,html文件和静态文件还是上面的。

python代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2019/2/17 14:06
# @Author : wuchao
# @Site :
# @File :
# @Software: PyCharmimport socket
from threading import Thread
#注意一点,不开多线程完全是可以搞定的,在这里只是教大家要有并发编程的思想,所以我使用了多线程
sk = ()
(('',8001))
()def func1(conn):with open('', 'rb') as f:# with open('Python开发.html','rb') as f:data = ()(data)()def func2(conn):with open('', 'rb') as f:pic_data = ()# (b'HTTP/1.1 200 ok \r\n\r\n') (pic_data)()def func3(conn):with open('', 'rb') as f:css_data = ()(css_data)()def func4(conn):with open('', 'rb') as f:ico_data = ()(ico_data)()def func5(conn):with open('', 'rb') as f:js_data = ()(js_data)()while 1:conn,addr = ()# while 1:from_b_msg = (1024)str_msg = ('utf-8')path = ('\r\n')[0].split('')[1]print('path>>>',path)(b'HTTP/1.1 200 ok \r\n\r\n')print(from_b_msg)if path == '/':# func1(conn)t = Thread(target=func1,args=(conn,))()elif path == '/':# func2(conn)t = Thread(target=func2, args=(conn,))()elif path == '/':# func3(conn)t = Thread(target=func3, args=(conn,))()elif path == '/':# func4(conn)t = Thread(target=func4, args=(conn,))()elif path == '/':# func5(conn)t = Thread(target=func5, args=(conn,))()

更更高级版web框架

if判断太多了,开线程的方式也比较恶心,有多少个if判断,就写多少次创建线程,简化一下:

import socket
from threading import Threadsk = ()
(('',8001))
()def func1(conn):(b'HTTP/1.1 200 ok\r\ncontent-type:text/html\r\ncharset:utf-8\r\n\r\n')with open('', 'rb') as f:# with open('Python开发.html','rb') as f:data = ()(data)()def func2(conn):(b'HTTP/1.1 200 ok\r\n\r\n')with open('', 'rb') as f:pic_data = ()# (b'HTTP/1.1 200 ok \r\n\r\n') (pic_data)()def func3(conn):(b'HTTP/1.1 200 ok\r\n\r\n')with open('', 'rb') as f:css_data = ()(css_data)()def func4(conn):(b'HTTP/1.1 200 ok\r\n\r\n')with open('', 'rb') as f:ico_data = ()(ico_data)()def func5(conn):(b'HTTP/1.1 200 ok\r\n\r\n')with open('', 'rb') as f:js_data = ()(js_data)()#定义一个路径和执行函数的对应关系,不再写一堆的if判断了
l1 = [('/',func1),('/',func2),('/',func3),('/',func4),('/',func5),
]#遍历路径和函数的对应关系列表,并开多线程高效的去执行路径对应的函数,def fun(path,conn):for i in l1:if i[0] == path:t = Thread(target=i[1],args=(conn,))()# else:# (b'sorry')while 1:conn,addr = ()#看完这里面的代码之后,你就可以思考一个问题了,很多人要同时访问你的网站,你在请求这里是不是可以开起并发编程的思想了,多进程+多线程+协程,妥妥的支持高并发,再配合服务器集群,这个网页就支持大量的高并发了,有没有很激动,哈哈,但是咱们写的太low了,而且功能很差,容错能力也很差,当然了,如果你有能力,你现在完全可以自己写web框架了,写一个nb的,如果现在没有这个能力,那么我们就来好好学学别人写好的框架把,首先第一个就是咱们的django框架了,其实就是将这些功能封装起来,并且容错能力强,抗压能力强,总之一个字:吊。# while 1:from_b_msg = (1024)str_msg = ('utf-8')path = ('\r\n')[0].split('')[1]print('path>>>',path)# 注意:因为开启的线程很快,可能导致你的文件还没有发送过去,其他文件的请求已经来了,导致你文件信息没有被浏览器正确的认识,所以需要将发送请求行和请求头的部分写道前面的每一个函数里面去,并且防止出现浏览器可能不能识别你的html文件的情况,需要在发送html文件的那个函数里面的发送请求行和请求头的部分加上两个请求头content-type:text/html\r\ncharset:utf-8\r\n# (b'HTTP/1.1 200 ok\r\n\r\n') 不这样写了# (b'HTTP/1.1 200 ok\r\ncontent-type:text/html\r\ncharset:utf-8\r\n\r\n') 不这样写了print(from_b_msg)#执行这个fun函数并将路径和conn管道都作为参数传给他fun(path,conn)

根据不同路径返回不同页面的web框架

既然知道了我们可以根据不同的请求路径来返回不同的内容,那么我们可不可以根据用户访问的不同路径,返回不同的页面啊,嗯,应该是可以的

自己创建两个html文件,写几个标签在里面,名为和,然后根据不同的路径返回不同的页面,我就给大家写上python代码吧:

"""
根据URL中不同的路径返回不同的内容
返回独立的HTML页面
"""import socket
sk = ()
(("", 8080)) # 绑定IP和端口
() # 监听# 将返回不同的内容部分封装成函数def index(url):# 读取页面的内容with open("", "r", encoding="utf8") as f:s = ()# 返回字节数据return bytes(s, encoding="utf8")def home(url):with open("", "r", encoding="utf8") as f:s = ()return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]while 1:# 等待连接conn, add = ()data = (8096) # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = ("\r\n")[0]url = ()[1] # url是我们从浏览器发过来的消息中分离出的访问路径(b'HTTP/1.1 200 OK\r\n\r\n') # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容func = None # 定义一个保存将要执行的函数名的变量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具体的响应消息 (response)()

八、返回动态页面的web框架

这网页能够显示出来了,但是都是静态的啊。页面的内容都不会变化的,我想要的是动态网站,动态网站的意思是里面有动态变化的数据,而不是页面里面有动态效果,这个大家要注意啊。

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

"""
根据URL中不同的路径返回不同的内容
返回HTML页面
让网页动态起来
"""import socket
import timesk = ()
(("", 8080)) # 绑定IP和端口
() # 监听# 将返回不同的内容部分封装成函数def index(url):with open("", "r", encoding="utf8") as f:s = ()now = str(())s = ("@@oo@@", now) # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号return bytes(s, encoding="utf8")def home(url):with open("", "r", encoding="utf8") as f:s = ()return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]while 1:# 等待连接conn, add = ()data = (8096) # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = ("\r\n")[0]url = ()[1] # url是我们从浏览器发过来的消息中分离出的访问路径(b'HTTP/1.1 200 OK\r\n\r\n') # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容func = None # 定义一个保存将要执行的函数名的变量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具体的响应消息 (response)()

这八个框架让大家满意了吧,这下子明白整个web框架的原理了吧,哈哈,但是我们写的框架还是太low了,不够强壮,那别人已经开发好了很多nb的框架了,如:Django、Flask、Tornado等等,我们学学怎么用就可以啦,但是注意一个问题,我们在里面获取路径的时候,我们是按照\r\n来分割然后再通过空格来分割获取到的路径,但是如果不是http协议的话,你自己要注意消息格式了。

接下来我们看一个别人写好的模块来搞的web框架,这个模块叫做wsgiref

九、wsgiref模块版web框架

         wsgiref模块其实就是将整个请求信息给封装了起来,就不需要你自己处理了,假如它将所有请求信息封装成了一个叫做request的对象,那么你直接就能获取到用户这次请求的路径,就能获取到本次用户请求的请求方式(get还是post)等,那这个模块用起来,我们再写web框架是不是就简单了好多啊。

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

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

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

  这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。

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

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

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

  好,接下来我们就看一下(能理解就行,了解就可以了):先看看wsfiref怎么使用

from wsgiref.simple_server import make_server
# wsgiref本身就是个web框架,提供了一些固定的功能(请求和响应信息的封装,不需要我们自己写原生的socket了也不需要咱们自己来完成请求信息的提取了,提取起来很方便)
#函数名字随便起def application(environ, start_response):''':param environ: 是全部加工好的请求信息,加工成了一个字典,通过字典取值的方式就能拿到很多你想要拿到的信息:param start_response: 帮你封装响应信息的(响应行和响应头),注意下面的参数:return:'''start_response('200 OK', [('k1','v1'),])print(environ)print(environ['PATH_INFO']) #输入地址:8000,这个打印的是'/',输入的是:8000/index,打印结果是'/index'return [b'

Hello, web!

']#和咱们学的socketserver那个模块很像啊
httpd = make_server('', 8080, application)print('Serving HTTP on port 8080...')
# 开始监听HTTP请求:
()

来一个完整的web项目,用户登录认证的项目,我们需要连接数据库了,所以先到mysql数据库里面准备一些表和数据

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: 0mysql> select * from userinfo;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | chao | 666 |
| 2 | sb1 | 222 |
+----+----------+----------+
2 rows in set (0.00 sec)

然后再创建这么几个文件:

python文件名称,内容如下:

#创建表,插入数据def createtable():import pymysqlconn = (host='',port=3306,user='root',password='666',database='db1',charset='utf8')cursor = ()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');'''(sql)()()()

python的名为webauth文件,内容如下:

#对用户名和密码进行验证def auth(username,password):import pymysqlconn = (host='',port=3306,user='root',password='123',database='db1',charset='utf8')print('userinfo',username,password)cursor = ()sql = 'select * from userinfo where username=%s and password=%s;'res = (sql, [username, password])if res:return Trueelse:return False

用户输入用户名和密码的文件,名为,内容如下:

用户名密码

用户验证成功后跳转的页面,显示成功,名为,内容如下:

宝贝儿,恭喜你登陆成功啦

python服务端代码(主逻辑代码),名为:

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('','rb') as f:data = ()#针对form表单提交的auth路径,进行对应的逻辑处理elif path == '/auth/':#登陆认证#1.获取用户输入的用户名和密码#2.去数据库做数据的校验,查看用户提交的是否合法# user_information = environ['']if ("REQUEST_METHOD") == "POST":#获取请求体数据的长度,因为提交过来的数据需要用它来提取,注意POST请求和GET请求的获取数据的方式不同try:request_body_size = int(('CONTENT_LENGTH', 0))except (ValueError):request_body_size = 0#POST请求获取数据的方式request_data = environ[''].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请求的返回数据我就不写啦       passif ("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 = (username,password)if status:# 3.将相应内容返回with open('','rb') as f:data = ()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('', 8080, application)print('Serving HTTP on port 8080...')
# 开始监听HTTP请求:
()

把代码拷走,创建文件,放到同一个目录下,运行一下文件的代码就能看到效果,注意先输入的网址是:8080/login ,还要注意你的mysql数据库没有问题。b172dadc314bfc3794ef856a91f446fc.png

十、起飞版web框架

我们上一个web框架把所有的代码都写在了一个py文件中,我们拆到其他文件里面去,并且针对不用的路径来进行分发请求的时候都用的if判断,很多值得优化的地方,好,结合我们前面几个版本的优势我们来优化一下,分几个文件和文件夹

代码就不在博客上都列出来了,我打包放到百度云上了,大家去下载看看把:

将来要说的MVC框架是什么呢:

M:  就是和数据库打交道用的,创建表等操作

V:View  视图(视图函数,html文件)

C:controller  控制器(其实就是我百度云代码里面那个urls文件里面的内容,url(路径)分发与视图函数的逻辑处理)

Django叫做MTV框架

M:  就是和数据库打交道用的,创建表等操作(和上面一样)

T:templates  存放HTML文件的

V:View 视图函数(逻辑处理)

其实你会发现MTV比MVC少一个url分发的部分

所以我们学的django还要学一个叫做url控制器(路径分发)的东西,MTV+url控制器就是我们django要学的内容。     

模板渲染JinJa2

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

  下载:

一个html文件,index2,html,内容如下:

姓名:{{name}}

爱好:

    {% for hobby in hobby_list %}
  • {{hobby}}
  • {% endfor %}

使用jinja2渲染文件,创建一个python文件,代码如下:

from wsgiref.simple_server import make_server
from jinja2 import Templatedef index():with open("", "r",encoding='utf-8') as f:data = ()template = Template(data) # 生成模板文件ret = ({"name": "于谦", "hobby_list": ["烫头", "泡吧"]}) # 把数据填充到模板里面return [bytes(ret, encoding="utf8"), ]# 定义一个url和函数的对应关系
URL_LIST = [("/index/", index),
]def run_server(environ, start_response):start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息url = environ['PATH_INFO'] # 取到用户输入的urlfunc = None # 将要执行的函数for i in URL_LIST:if i[0] == url:func = i[1] # 去之前定义好的url列表里找url应该执行的函数breakif func: # 如果能找到要执行的函数return func() # 返回函数的执行结果else:return [bytes("404没有该页面", encoding="utf8"), ]if__name__ == '__main__':httpd = make_server('', 8000, run_server)print("Serving HTTP on port 8000...")()

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

使用pymysql连接数据库

conn = (host="", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
cursor = (cursor=)
("select name, age, department_id from userinfo")
user_list = ()
()
()

创建一个测试的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的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。

MVC和MTV框架

MVC

Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:

083d603543fab9351a39d75102c9cc82.png

MTV

Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:

  • M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
  • T 代表模板 (Template):负责如何把页面展示给用户(html)。
  • V 代表视图(View):   负责业务逻辑,并在适当时候调用Model和Template。

除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:

73ce2fff26dd2fc490df315f4bdf74f3.png

一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。

Django下载安装

Django官网下载页面

下载Django:

pip3 install django==

创建一个django project

django-admin startproject mysite 创建了一个名为"mysite"的Django 项目:

88a036bfb034a44e2c627eff8d58dae7.png

当前目录下会生成mysite的工程,目录结构如下:(大家注意昂,pip下载下来的django你就理解成一个模块,而不是django项目,这个模块可以帮我们创建django项目)

309406e6096dcd362f0ad1c5b4578676.png

  •  ----- Django项目里面的工具,通过它可以调用django shell和数据库,启动关闭项目与项目交互等,不管你将框架分了几个文件,必然有一个启动文件,其实他们本身就是一个文件。
  •  ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
  •  ----- 负责把URL模式映射到应用程序。
  • wsgi.py ---- runserver命令就使用wsgiref模块做简单的web server,后面会看到renserver命令,所有与socket相关的内容都在这个文件里面了,目前不需要关注它。

python runserver :8080 #此时已经可以启动django项目了,只不过什么逻辑也没有呢

你会发现,上面没有什么view视图函数的文件啊,这里我们说一个应用与项目的关系,上面我们只是创建了一个项目,并没有创建应用,以微信来举例,微信是不是一个大的项目,但是微信里面是不是有很多个应用,支付应用、聊天应用、朋友圈、小程序等这些在一定程度上都是相互独立的应用,也就是说一个大的项目里面可以有多个应用,也就是说项目是包含应用的,它没有将view放到这个项目目录里面是因为它觉得,一个项目里面可以有多个应用,而每个应用都有自己这个应用的逻辑内容,所以他觉得这个view应该放到应用里面,比如说我们的微信,刚才说了几个应用,这几个应用的逻辑能放到一起吗,放到一起是不是就乱套啦,也不好管理和维护,所以这些应用的逻辑都分开来放,它就帮我们提炼出来了,提炼出来一个叫做应用的东西,所以我们需要来创建这个应用。

在mysite目录下创建应用

python startapp blog #通过执行文件来创建应用,执行这句话一定要注意,你应该在这个的文件所在目录下执行这句话,因为其他目录里面没有这个文件
python startapp blog2 #每个应用都有自己的目录,每个应用的目录下都有自己的视图函数和数据库操作相关的文件

d4bcc78b7bbff28332d64588513bc666.png

我们现在只需要看其中两个文件

:之前我们写的那个名为model的文件就是创建表用的,这个文件就是存放与该app(应用)相关的表结构的

    :存放与该app相关的视图函数的

启动django项目

python runserver 8080 # python runserver :8080,本机就不用写ip地址了 如果连端口都没写,默认是本机的8000端口

这样我们的django就启动起来了!当我们访问:http://:8080/时就可以看到:

9c50f113e7f837c94d1f2d170c5a494e.png

学习Django,我们就学上面的这些文件,怎么在MTV+url分发的功能下来使用。

最后我们说一下,其实我们将来创建django项目,很少用命令行了,就用pycharm来创建,怎么创建呢?看图:

7d79acc26bd5187526bbc9462e97a36d.png

86206279983ee1850bb36f171a7d0c2b.png

看项目目录:

276b352af1b12abf1b9813352d259f9c.png

基于Django实现一个简单的示例

现在实现一个用户输入一个timer路径,返回一个含有当前时间的页面,想想怎么做?用户输入网址-->路径-->函数-->返回数据(文件)

url控制器(第一步就找它)

django 版本的url写法:from django.conf.urls import urlfrom django.contrib import adminfrom crm import viewsurlpatterns = [ url(r'^admin/', ), url(r'^index/', ),]
下面是版本的url写法,不太一样了,但是兼容的,不过我们现在还是主要说x版本的,所以写url的时候按照上的方式写。from django.contrib import admin
from django.urls import path#找对应的函数,是哪个app里面的函数from app01 import viewsurlpatterns = [path('admin/', ), #这个先不用管,后面会学path('index/',),
]

视图

from django.shortcuts import render,HttpResponse# Create your views here.
#逻辑和返回数据def index(request):import datetimenow=()ctime=("%Y-%m-%d %X")#return HttpResponse('哈哈,好玩吗?')return render(request,"",{"ctime":ctime}) #render,渲染html页面文件并返回给浏览器

模板

当前时间:{{ ctime }}

通过pycharm来运行项目:

b0e67b550333a4226ede924bf56ad522.png

看控制台:

5a55f83af34a719cd54149df142c5815.png

执行效果如下:

e95d70e2b846b0966f7f540bbd88c19f.png

有同学说:我想自己配置启动的端口怎么搞啊:

3674a4adc4c518e309e7ae8deee6e27c.png

d1caf25c8edf08b46eea07a3e5a14f0f.png

还有一点说一下昂,在settings配置文件里面有关于templates(放html文件的配置):

TEMPLATES = [{'BACKEND': '','DIRS': [(BASE_DIR, 'templates')] #有些版本的django没有写这个,自己写一下,就是配置一个django找html文件的路径,render方法就来这里找html文件 ,'APP_DIRS': True,'OPTIONS': {'context_processors': ['','','','',],},},
]

关于请求和响应的请求信息和相应信息的设置还需要你自己写吗?之前我们用wsgiref是不是还写来着,现在都不需要写了,简单不。

还有一点:post请求的时候你会发现一个 Forbidden的错误:

5cb64b0ee8aaab39b123aee584f51110.png

现在只需要做一步,在settings配置文件里面将这一行注释掉,这是django给你加的一个csrf的认证,现在不需要,我们会讲的

MIDDLEWARE = ['','','',# '','','','',
]

还记得django写视图函数的时候,有一个参数是必须要给的吗,叫做request,如果你是post请求,那么就用,就能拿到post请求提交过来的所有数据(一个字典,然后再通过字典取值.get('username'),取出来的就是个字符串,你在那个字典里面看到的是{'username':['chao']},虽然看着是列表,但是.get('username')取出来的就是个字符串),通过就能拿到提交过来的所有数据,而且记着,每一个视图函数都要给人家返回一些内容,用render或者HttpResponse等,其实render里面也是通过HttpResponse来返回内容,不然会报错,错误是告诉你没有返回任何内容:

d59a1535d8c902fe57660047ee13c35d.png




推荐阅读
  • vue引入echarts地图的四种方式
    一、vue中引入echart1、安装echarts:npminstallecharts--save2、在main.js文件中引入echarts实例:  Vue.prototype.$echartsecharts3、在需要用到echart图形的vue文件中引入:   importechartsfrom"echarts";4、如果用到map(地图),还 ... [详细]
  • 使用HTML和JavaScript实现视频截图功能
    本文介绍了如何利用HTML和JavaScript实现从远程MP4、本地摄像头及本地上传的MP4文件中截取视频帧,并展示了具体的实现步骤和示例代码。 ... [详细]
  • 利用python爬取豆瓣电影Top250的相关信息,包括电影详情链接,图片链接,影片中文名,影片外国名,评分,评价数,概况,导演,主演,年份,地区,类别这12项内容,然后将爬取的信息写入Exce ... [详细]
  • 本文详细介绍了如何使用Python中的smtplib库来发送带有附件的邮件,并提供了完整的代码示例。作者:多测师_王sir,时间:2020年5月20日 17:24,微信:15367499889,公司:上海多测师信息有限公司。 ... [详细]
  • 自然语言处理(NLP)——LDA模型:对电商购物评论进行情感分析
    目录一、2020数学建模美赛C题简介需求评价内容提供数据二、解题思路三、LDA简介四、代码实现1.数据预处理1.1剔除无用信息1.1.1剔除掉不需要的列1.1.2找出无效评论并剔除 ... [详细]
  • 本文详细介绍了如何使用JavaScript实现面部交换功能,包括基本原理和具体实现步骤。 ... [详细]
  • python模块之正则
    re模块可以读懂你写的正则表达式根据你写的表达式去执行任务用re去操作正则正则表达式使用一些规则来检测一些字符串是否符合个人要求,从一段字符串中找到符合要求的内容。在 ... [详细]
  • Python多线程详解与示例
    本文介绍了Python中的多线程编程,包括僵尸进程和孤儿进程的概念,并提供了具体的代码示例。同时,详细解释了0号进程和1号进程在系统中的作用。 ... [详细]
  • 一个建表一个执行crud操作建表代码importandroid.content.Context;importandroid.database.sqlite.SQLiteDat ... [详细]
  • 深入解析HTML5字符集属性:charset与defaultCharset
    本文将详细介绍HTML5中新增的字符集属性charset和defaultCharset,帮助开发者更好地理解和应用这些属性,以确保网页在不同环境下的正确显示。 ... [详细]
  • 探讨了 Python 中 UTF-8 编码的中文字符在某些情况下被误识别为 GB2312 的问题,并提供了详细的代码示例和环境信息。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 第二十五天接口、多态
    1.java是面向对象的语言。设计模式:接口接口类是从java里衍生出来的,不是python原生支持的主要用于继承里多继承抽象类是python原生支持的主要用于继承里的单继承但是接 ... [详细]
author-avatar
mobiledu2502883857
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有