python框架之虚拟环境配置
1. web框架
web服务器:web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序。目前最主流的三个web服务器是Apache、Nginx。IIS。
web框架:是一种开发框架,用来支持动态网站、网络应用程序及网络服务的开发
WSGI:web服务器网关接口(python Web Server Gateway Interface),是为Python语言定义的web服务器和web应用程序或框架之间的一种简单而通用的接口
静态资源:不需要经常变化的资源,这种资源web服务器可以提前准备好,比如:png/jpg/css/js等文件
动态资源:和静态资源相反,这种资源会经常变化,web服务器无法提前准备好,需要web框架来帮web服务器进行准备,在这里服务器可以把.html的资源请求认为是动态资源请求交由web框架进行处理
2. 开发自己的简单web框架
- 如果请求资源路径的后缀名是.html则是动态资源请求,让web框架进行处理
- 静态资源请求,让web服务器进行处理
1、开发web服务器主体程序
- 接收客户端HTTP请求(TCP协议)
- 判断请求是否是静态资源还是动态资源
- 静态资源的处理
- 动态资源的处理
- 关闭web服务器
my_web.py
import socket
import threading
import MyFramework
# 开发自己的web服务器主类
class MyHttpWebServer(object):
def __init__(self,port):
# 创建http服务的套接字
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#设置端口号复用,程序退出之后不需要等待几分钟,直接释放端口
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
server_socket.bind(('',port))
server_socket.listen(128)
self.server_socket = server_socket
# 处理浏览器请求的函数
@staticmethod
def handle_browser_request(new_socket):
# 接收客户端发过来的数据
recv_data = new_socket.recv(4096)
# 如果没有收到数据,那么请求无效,关闭套接字,直接退出
if len(recv_data) == 0:
new_socket.close()
return
# 对接收的字节数据,转换成字符数据
request_data = recv_data.decode('utf-8')
# print('浏览器请求的数据:',request_data)
request_lst = request_data.split(' ',maxsplit=2)
# 得到请求路径
request_path = request_lst[1]
# print('请求路径是:',request_path)
if request_path == '/': # 如果请求路径为根目录,自动设置为/index.html
request_path = '/index.html'
# 根据请求路径,来判断是动态资源还是静态资源
if request_path.endswith('.html'):
# 动态资源的请求
# 动态资源交给web框架来处理,需要把请求参数传给web框架,可能会有多个参数,所以采用字典结构
params={
'request_path':request_path,
}
# web框架处理动态资源请求之后,返回一个响应
response = MyFramework.handle_request(params)
new_socket.send(response)
new_socket.close()
else:
# 静态资源的请求
# 起始就是根据请求路径读取目录/static中的静态文件数据,响应给客户端
response_body = None
response_first_line = None
try:
# 读取static目录中对应的文件数据,rb模式:是一种兼容模式,可以打开图片,也可以打开JS文件
with open('static'+request_path,'rb') as f:
response_body = f.read()
response_first_line = 'HTTP/1.1 200 OK\r\n'
except Exception as e:# 浏览器想读取的文件可能不存在
with open('static/404.html','rb') as f:
response_body = f.read() # 响应主体页面内容(字节数据)
response_first_line = 'HTTP/1.1 404 Not Found\r\n'
finally:
# 响应头(字符数据)
response_header = 'Server: Apache\r\n'
# 组成响应数据,发送给客户端浏览器
response = (response_first_line+response_header + '\r\n').encode('utf-8')+response_body
new_socket.send(response)
new_socket.close()
# 启动服务器,并且接收客户端的请求
def start(self):
# 循环并且多线程来接收客户端的请求
while True:
new_socket,ip_port = self.server_socket.accept()
# print('客户端的ip和端口',ip_port)
# 一个客户端请求交给一个线程处理
sub_thread = threading.Thread(target=self.handle_browser_request,args=(new_socket,))
sub_thread.setDaemon(True) #设置当前线程为守护线程
sub_thread.start() # 启动子线程
# web服务器程序的入口
def main():
web_server = MyHttpWebServer(8080)
web_server.start()
if __name__ == '__main__':
main()
2、开发web框架主体程序
- 根据请求路径,动态的响应对应的数据
- 如果请求路径没有对应的响应数据也需要返回404页面
MyFramework.py
# 处理动态资源请求的参数
import time
def handle_request(params):
request_path = params.get('request_path')
if request_path == '/index.html':# 当前的请求路径有与之对应的动态响应,当前框架值开发了index.html的功能
response = index()
elif request_path == '/userinfo.html': # 个人中心的功能,user_info.html
response = user_info()
else:
# 没有动态资源的数据,返回404页面
response = page_not_found()
return response
# 当前index函数,专门处理index.html的请求
def index():
# 需求:在页面中动态
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/index.html','r',encoding='utf-8') as f:
response_body = f.read()
datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}',datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 专门处理userinfo.html的动态请求
def user_info():
# 需求:在页面中动态
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/user_info.html', 'r', encoding='utf-8') as f:
response_body = f.read()
datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}', datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 处理没有找到对应的动态资源
def page_not_found():
with open('static/404.html', 'rb') as f:
response_body = f.read() # 响应主体页面内容(字节数据)
response_first_line = 'HTTP/1.1 404 Not Found\r\n'
response_header = 'Server: Apache\r\n'
# 组成响应数据,发送给客户端浏览器
response = (response_first_line + response_header + '\r\n').encode('utf-8') + response_body
return response
3、使用模板显示响应内容
- 自己设计一个模板(index.html),有一些地方采用动态的数据来代替
- 需要替代的数据有哪些
index.html
<!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>
<link href="../css/bootstrap.min.css" rel="stylesheet">
<script src="../js/jquery-1.12.4.min.js"></script>
<script src="../js/bootstrap.min.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="#" class="navbar-brand">电影列表</a>
</div>
<div class="collapse navbar-collapse" id="mymenu">
<ul class="nav navbar-nav">
<li class="active"><a href="">电影信息</a> </li>
<li><a href="">个人中心</a></li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="container-fluid">
<table class="table table-hover">
<tr>
<th>序号</th>
<th>名称</th>
<th>导演</th>
<th>上映时间</th>
<th>票房</th>
<th>电影时长</th>
<th>类型</th>
<th>备注</th>
<th>删除电影</th>
</tr>
{%datas%}
</table>
</div>
</div>
</body>
</html>
user_info.html
<!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>
<link href="../css/bootstrap.min.css" rel="stylesheet">
<script src="../js/jquery-1.12.4.min.js"></script>
<script src="../js/bootstrap.min.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="#" class="navbar-brand">个人中心</a>
</div>
<div class="collapse navbar-collapse" id="mymenu">
<ul class="nav navbar-nav">
<li ><a href="">电影信息</a> </li>
<li class="active"><a href="">个人中心</a></li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="container-fluid">
<table class="table table-hover">
<tr>
<th>用户名</th>
<th>密码</th>
<th>年龄</th>
<th>性别</th>
</tr>
{%datas%}
</table>
</div>
</div>
</body>
</html>
404.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<meta charset="UTF-8">
<title>404 资源没有发现</title>
</head><body>
<h1>资源没有发现</h1>
</body></html>
4、开发路由的列表功能
- 以后开发新的动态资源的功能,只需要增加一个条件判断分支,增加一个专门处理的函数
- 路由:就是请求的URL路径和处理函数之间的映射
- 路由表
请求路径 | 处理函数 |
---|---|
/index.html | index函数 |
/userinfo.html | user_info函数 |
注意:用户的动态资源请求,通过遍历路由表找到对应的函数来完成
MyFramework.py
# 处理动态资源请求的参数
import time
def handle_request(params):
request_path = params.get('request_path')
for path,func in route_list:
if path == request_path:
response = func()
break
else:
response = page_not_found()
return response
# 当前index函数,专门处理index.html的请求
def index():
# 需求:在页面中动态
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/index.html','r',encoding='utf-8') as f:
response_body = f.read()
datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}',datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 专门处理userinfo.html的动态请求
def user_info():
# 需求:在页面中动态
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/user_info.html', 'r', encoding='utf-8') as f:
response_body = f.read()
datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}', datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 处理没有找到对应的动态资源
def page_not_found():
with open('static/404.html', 'rb') as f:
response_body = f.read() # 响应主体页面内容(字节数据)
response_first_line = 'HTTP/1.1 404 Not Found\r\n'
response_header = 'Server: Apache\r\n'
# 组成响应数据,发送给客户端浏览器
response = (response_first_line + response_header + '\r\n').encode('utf-8') + response_body
return response
#定义路由表
route_list = {
('/index.html',index),
('/userinfo.html',user_info)
}
5、采用装饰器的方式添加路由
- 采用带参数的路由器
- 在任何一个处理函数的基础上添加一个路由的功能
MyFramework.py
# 处理动态资源请求的参数
import time
from functools import wraps
route_list=[]
# 定义一个带参数的装饰器
def route(request_path): # 参数就是url请求
def add_route(func):
# 添加路由到路由表
route_list.append((request_path,func))
# print(route_list)
@wraps(func)
def invoke(*args,**kwargs):
# 调用指定的处理函数,并且返回结果
return func()
return invoke
return add_route
def handle_request(params):
request_path = params.get('request_path')
for path,func in route_list:
if path == request_path:
response = func()
break
else:
response = page_not_found()
return response
# 当前index函数,专门处理index.html的请求
@route(request_path='/index.html')
def index():
# 需求:在页面中动态
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/index.html','r',encoding='utf-8') as f:
response_body = f.read()
datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}',datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 专门处理userinfo.html的动态请求
@route(request_path='/userinfo.html')
def user_info():
# 需求:在页面中动态
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/user_info.html', 'r', encoding='utf-8') as f:
response_body = f.read()
datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}', datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 处理没有找到对应的动态资源
def page_not_found():
with open('static/404.html', 'rb') as f:
response_body = f.read() # 响应主体页面内容(字节数据)
response_first_line = 'HTTP/1.1 404 Not Found\r\n'
response_header = 'Server: Apache\r\n'
# 组成响应数据,发送给客户端浏览器
response = (response_first_line + response_header + '\r\n').encode('utf-8') + response_body
return response
6、电影列表页面的开发
- 查询数据
- 根据查询的数据得到动态的内容
只需要修改index函数,增加数据库查询,将html页面的数据进行替换即可
MyFramework.py
import time
from functools import wraps
import pymysql
route_list=[]
# 定义一个带参数的装饰器
def route(request_path): # 参数就是url请求
def add_route(func):
# 添加路由到路由表
route_list.append((request_path,func))
# print(route_list)
@wraps(func)
def invoke(*args,**kwargs):
# 调用指定的处理函数,并且返回结果
return func()
return invoke
return add_route
def handle_request(params):
request_path = params.get('request_path')
for path,func in route_list:
if path == request_path:
response = func()
break
else:
response = page_not_found()
return response
# 当前index函数,专门处理index.html的请求
@route(request_path='/index.html')
def index():
# 需求:从数据库中取得所有的电影数据,并且动态展示
# 1. 在mysql中查询数据
conn = pymysql.connect(host='localhost',port=3306,user='admin',password='admin123',database='mytestdb',charset='utf8')
cursor = conn.cursor()
cursor.execute('select * from t_movies')
result = cursor.fetchall()
print(result)
# 把查询的数据转换成动态内容
datas = ""
for row in result:
datas += '''
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s 亿人民币</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td><input type="button" value="删除"/></td>
</tr>
''' %row
print(datas)
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/index.html','r',encoding='utf-8') as f:
response_body = f.read()
# datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}',datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 专门处理userinfo.html的动态请求
@route(request_path='/userinfo.html')
def user_info():
# 需求:在页面中动态
response_first_line = 'HTTP/1.1 200 OK\r\n'
with open('template/user_info.html', 'r', encoding='utf-8') as f:
response_body = f.read()
datas = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
response_body = response_body.replace('{%datas%}', datas)
response_header = 'Server: Apache\r\n'
response = (response_first_line + response_header + '\r\n' + response_body + '\r\n').encode('utf-8')
return response
# 处理没有找到对应的动态资源
def page_not_found():
with open('static/404.html', 'rb') as f:
response_body = f.read() # 响应主体页面内容(字节数据)
response_first_line = 'HTTP/1.1 404 Not Found\r\n'
response_header = 'Server: Apache\r\n'
# 组成响应数据,发送给客户端浏览器
response = (response_first_line + response_header + '\r\n').encode('utf-8') + response_body
return response
3、虚拟环境介绍
虚拟环境,是一个虚拟化,从电脑独立开发出来的环境。通俗的来讲,虚拟环境就借助虚拟机来把一部分内容独立出来,我们把这部分独立出来的东西称作容器。在这个容器中,我们可以只安装我们需要的依赖包,各个容器之间相互隔离,互不影响。
4、为什么使用虚拟环境
- 项目部署时,直接导出项目对应的环境中的库就可以了
- 同时开发多个项目,各自项目使用的python版本不同,譬如一个是python2,一个是python3,那么就需要来回的切换多个版本
- 当同时开发多个项目时,特别是多个项目使用同一个库,多个项目使用一个模块的不同版本,就需要来回的卸载和安装不同的版本,因为同一个python环境中,同名的库只能有一个版本
5、虚拟环境的安装
安装虚拟环境库
pip install virtualenv
6、虚拟环境优化
在使用过程中,通过安装virtualwrapper-win可以更加简便的使用虚拟环境
- 安装
pip install virtualenvwrapper-win
- 配置环境变量
- 新建系统变量名:WORKON_HOME
- 变量值配置为一个指定目录:D:\env
- 在盘符中创建相应文件
- 保存配置
- 在cmd中运行workon或isvirtualenv可查看当前的虚拟环境配置情况
- 新建虚拟环境
mkvirtualenv env-name
注意:可以在cmd中任意路径下执行语句,创建的环境都会保存在配置的环境变量下的路径中
5. 激活虚拟环境
workon env-name
- 退出虚拟环境
deactivate
- 删除虚拟环境
rmvirtualenv env-name
库只能有一个版本
## 5、虚拟环境的安装
安装虚拟环境库
```shell
pip install virtualenv
6、虚拟环境优化
在使用过程中,通过安装virtualwrapper-win可以更加简便的使用虚拟环境
- 安装
pip install virtualenvwrapper-win
- 配置环境变量
- 新建系统变量名:WORKON_HOME
- 变量值配置为一个指定目录:D:\env
- 在盘符中创建相应文件
- 保存配置
- 在cmd中运行workon或isvirtualenv可查看当前的虚拟环境配置情况
- 新建虚拟环境
mkvirtualenv env-name
注意:可以在cmd中任意路径下执行语句,创建的环境都会保存在配置的环境变量下的路径中
5. 激活虚拟环境
workon env-name
- 退出虚拟环境
deactivate
- 删除虚拟环境
rmvirtualenv env-name