建议在看这一章节前,先了解一下HTTP协议的组成:HTTP协议
前言:
在了解Django之前,我们可以先了解web框架,了解它的好处是什么呢?在一步步搭建它的过程中,我们会逐步明白到Django是如何写的,以及如果处理页面接收与反馈给页面数据的。当然 这样讲可能有点抽象,那么我们先来了解一下吧!
什么是web框架?
Web框架是用来进行Web应用开发的一个软件架构。主要用于动态网络开发。开发者在基于Web框架实现自己的业务逻辑。Web框架实现了很多功能,为实现业务逻辑提供了一套通用方法。
- 简而言之:通过web框架可以实现在网络上访问我们的web应用
Python主流三大Web框架
1、DJango:重量级框架
Django是基于Python的免费和开放源代码Web框架,它遵循模型-模板-视图(MTV)体系结构模式。它封装的的功能常丰富且非常多所以它是重量级,Django的文档最完善、市场占有率最高、招聘职位最多。但如果需要实现的功能很少就会略显笨重
2、Flask:轻量级框架
Flask 是 Python 编写的一种轻量级 ( 微 ) 的 Web 开发框架,只提供 Web 框架的核心功能,较其他类型的框架更为的自由、灵活、更加适合高度定制化的 Web 项目。Flask 在功能上面没有欠缺,Flask的第三方开源组件比丰富,因此 Flask 对开发人员的水平有了一定的要求。使用Flask开发较依赖于第三方组件
3、Tornado:异步非阻塞框架
Tornado是一种 Web 服务器软件的开源版本。Tornado 和主流Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快,得利于其非阻塞的方式和对epoll的运用,Tornado 每秒可以处理数以千计的连接,因此 Tornado 是实时 Web 服务的一个 理想框架。但很多功能都需要开发者自己去编写
1、搭建web服务端
这里的web服务端是我们使用socket套接字来实现的,以浏览器为客户端 朝我们搭建的服务端发送数据,以及我们的服务端给浏览器返回数据的过程。
import socket
server = socket.socket()
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 重用端口
server.bind(('127.0.0.1',8080)) # 绑定ip与端口,供浏览器访问
server.listen(5)
while True:
conn, addr = server.accept() # 与访问的浏览器建立连接,进行数据接收与发送
receive = conn.recv(1024) # 接收浏览器发送的请求
print(receive) # 打印请求格式
conn.send(b'HTTP1.1/ 200 ok \n\n') # 服务端已经处理了浏览器发送的请求,返回状态
conn.send(b'Hello') # 响应浏览器一个Hello字符
此时我们打开浏览器:
2、使用wsgire模块
便于我们提取请求报文的内容,这里使用Python中一个更便于本次实验的模块:wsgiref
我们的代码只需要稍加变动,但效果还是和上面一致的。
from wsgiref.simple_server import make_server
def run(request,response): # 使用run函数来处理请求 以及响应数据,需要定义两个形参来接收请求。
'''
:param request: 客户端的请求数据
:param response: 给客户端进行响应的数据
:return:
'''
response('200 ok', []) # 返回响应状态给客户端
print(request) # 打印请求报文
return [b'World'] # 响应给客户端(浏览器)一个World字符
if __name__ == '__main__':
server = make_server('127.0.0.1',8080,run) # 分别代表:ip、端口、由哪个程序来处理请求
server.serve_forever() # 将服务器持续开启
用户的请求数据:打印出来是一个字典形式的
那么此时,我们在浏览器发送请求时,稍作变动。
比如:用户访问127.0.0.1:8080/index
,那么页面要出现index字符我们该如何实现呢。
首先服务端需要获取url后面的/index,才能进行处理。那么我们来代码实现吧
from wsgiref.simple_server import make_server
def run(request,response): # 使用run函数来处理请求 以及响应数据,需要定义两个形参来接收请求。
'''
:param request: 客户端的请求数据
:param response: 给客户端进行响应的数据
:return:
'''
response('200 ok', []) # 返回响应状态给客户端
# 获取ip+端口后面的内容,如:127.0.0.1:8080/index,我们就要获取/index
current_path = request['PATH_INFO']
# 一切用户请求的封装到了这个字典里面,而我们想要内容就在这个key里面
if current_path == '/index':
return [b'Index']
return [b'404 Error']
if __name__ == '__main__':
server = make_server('127.0.0.1',8080,run) # 分别代表:ip、端口、由哪个程序来处理请求
server.serve_forever() # 将服务器持续开启
如果再访问其它页面,那么服务端就会返回404 Error了。
现在我们的功能要拓展了,比如:用户要访问Login页面,并且该页面还要一些代码来专门处理用户请求,以及返回给用户一些数据。
按照上面的思路是不是一个页面对应一个if?那岂不是一个文件堆满了if嘛,所以我们需要将用户访问、以及处理响应用户的步骤进行拆分了。
3、文件拆分实现
我们需要先建立一个文件夹,里面存放这三个文件。
urls:用于表示用户输入的url应哪一个函数
'''
根据用户输入的url,返回该url对应的处理函数
'''
import views
url_handle = [ # 存放每个页面对应的处理函数
('/index',views.index),
('/login',views.login)
]
views:用于处理用户的请求与响应用户数据
'''
接收用户请求、在对应函数可以进行一番处理然后响应给用户数据。
'''
def index(request): # 接收用户请求
'''中间可以有处理过程'''
return 'index' # 将数据返回给调用这个函数的变量
def login(requets): # 接收用户请求
return 'login'
我们web框架的入口程序:
from wsgiref.simple_server import make_server
from urls import url_handle
def run(request,response): # 使用run函数来处理请求 以及响应数据,需要定义两个形参来接收请求。
'''
:param request: 客户端的请求数据
:param response: 给客户端进行响应的数据
:return:
'''
response('200 ok', []) # 返回响应状态给客户端
# 获取ip+端口后面的内容,如:127.0.0.1:8080/index,我们就要获取/index
current_path = request['PATH_INFO']
# 一切用户请求的封装到了这个字典里面,而我们想要内容就在这个key里面
judeg = False # 定义一个标识
func = '' # 定义一个变量,用于接收处理用户请求的函数返回的数据
for tuple_url in url_handle:
# 判断用户输入的页面地址,是否则在我们定义的处理列表里面
if current_path == tuple_url[0]:
func = tuple_url[1](request) # 调用对应的处理函数,并且将用户的请求传递给它,然后接收函数处理好并返回的数据;
judeg = True
break
if judeg:
return [func.encode('utf-8')]
return [b'404 Error'] # 上面判断失败,则说明用户输入的url不在我们定义的范围内,则返回404
if __name__ == '__main__':
server = make_server('127.0.0.1',8080,run) # 分别代表:ip、端口、由哪个程序来处理请求
server.serve_forever() # 将服务器持续开启
相信此时运行已经可以看到效果了,并且此后我们的入口文件再也不需要进行改动了。
如果需要再添加新的页面,那么我们只需要修改urls文件、与views文件。
- views添加对应url的处理函数
- urls添加url与处理函数绑定。
4、网页文件导入
我们返回给浏览器的可以是定义的字符串,也可以是HTML标签。我们创建一个HTML文件。
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>register</title>
</head>
<body>
<h1>注册界面</h1>
</body>
</html>
我们再views文件里面添加函数:
def register(request):
with open('register.html','rt') as f:
data = f.read()
return data
urls文件也做出增加:
import views
url_handle = [
('/index',views.index),
('/login',views.login),
('/register',views.register)
]
那么我们再访问:http://127.0.0.1:8080/register
就可以看到如下效果:
那么如何将我们的Python内容传递到页面,并且还支持取值操作呢?
那么就该今天的第二个主角登场了:jinja2模块
5、jinja2模块
jinja2是Flask作者开发的一个模板系统,起初是仿django模板的一个模板引擎,为Flask提供模板支持,由于其灵活,快速和安全等优点被广泛使用。
它具备自己的语法结构,当我们按照它的语法结构定义,那么就可以向对应的位置传值了。
实例:
from jinja2 import Template
data = '''
我是:{{ name }},今年:{{ age }}
'''
template = Template(data) # 先建立好一个模板
# 模板内可以接收name、age名称的数据,那么我们只需要使用:模板.render方法传入就可以
data = template.render({'name':'jack','age':18})
print(data)
打印结果:
'我是:jack,今年:18'
那么此时就明白了jinja2的作用了吧,现在我们将HTML页面也定义这种数据格式,然后在Python内把HTML文件的内容读取出来,再使用jinja2处理一下返回给浏览器。
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test.html</title>
</head>
<body>
<h1>{{ test_data }}</h1>
</body>
</html>
views.py
def test(request):
with open('test.html','rt') as f:
data = f.read()
from jinja2 import Template
template = Template(data)
data = template.render(test_data='我是在Python内处理了,然后才进行导入的')
return data
urls.py
'''
根据用户输入的url,返回该url对应的处理函数
'''
import views
url_handle = [ # 存放每个页面对应的处理函数
('/index',views.index),
('/login',views.login),
('/register',views.register),
('/test',views.test)
]
打开浏览器查看效果:
jinja2还支持循环,并且取值方式和python几乎相同。在此之前,我们先将所有的html文件存放到一个tempelates的文件夹,因为随着html文件越来越多,显的会非常的乱。
此时我们的目录结构:
那么现在来尝试一下jinja2的循环存入值吧!
先在templates文件夹下创建一个user_info.html的文件:
这里我们使用了前端框架:bootstrap,主要就是笔者不想写样式和效果啦
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>user_info</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.3/css/bootstrap.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<table class="table table-bordered table-hover table-striped text-center" style="width: 300px" align="center">
<thead>
<tr>
<td>Id</td>
<td>Name</td>
<td>Age</td>
</tr>
</thead>
<tbody>
{% for data in user_dic %}
<tr>
<td>{{ data.id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
views.py
def user_info(request):
with open('templates/user_info.html', 'rt') as f:
data = f.read()
template = Template(data)
dic = [
{'id':1,'name':'jack','age':18},
{'id':2,'name':'tom','age':19},
{'id':3,'name':'jams','age':23},
{'id':4,'name':'rouse','age':21},
]
data = template.render({'user_dic':dic})
return data
urls.py
import views
url_handle = [ # 存放每个页面对应的处理函数
('/index',views.index),
('/login',views.login),
('/register',views.register),
('/test',views.test),
('/user_info',views.user_info)
]
此时打开页面的效果:
当然,也可根据自身需求导入数据库,都是可以的。并且我们修改HTML的内容,再次刷新页面也可以同步过来,因为我们本身就是一个文件,每次访问到url地址都会执行函数然后再次加载HTML文件,所以达到了一个同步的效果。
最终我们的程序目录:
我们会发现,main文件从我们创建了views、urls后,再也没有操作过一次了,只是使用它来运行而已。
到了这里其实在往后写,本质上和写Django的区别也不是很大了,只是少了很多Django自带的一些功能,那么我们本章节的内容就是以上这些了。
如果本文对您有帮助,别忘一键3连,您的支持就是笔者最大的鼓励,感谢阅读!
下一章节传送门:Django基础
技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请
点赞 收藏+关注
子夜期待您的关注,谢谢支持!