1. Web框架介绍
-
描述:框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以快速开发特定的系统
-
本质:对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端
-
HTTP协议:规定了客户端和服务器之间的通信格式。每一个HTTP(请求和响应)都要遵守相同的格式,一个HTTP包含Header和Body两部分。
-
-
Body:HTML页面内容(Body本质是字符串,通过浏览器渲染HTML之后显示出页面)。Body是可选项
-
请求(request):客户端向服务端发送数据(服务端接收)
-
响应(response):服务端给客户端返回数据(客户端接收)
-
Web程序分为:服务器程序和应用程序
-
服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理
-
应用程序负责具体的逻辑处理
-
说明:为了方便应用程序的开发,出现了很多Web框架,服务器程序就需要为不同的框架提供不同的支持。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。此时就出现了一个标准化的规范,只要服务器程序支持这个标准,框架也支持这个标准,就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。
-
WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦
-
常用的WSGI服务器有uWSGI、Gunicorn。Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器
2. wsgiref模块的应用
# 标准版默认格式
from wsgiref.simple_server import make_server
def run_server(environ, start_response):
# 设置HTTP响应的状态码和头信息
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
return ['<h1>{}</h1>'.format(url).encode('utf8'), ]
if __name__ == '__main__':
add = ('127.0.0.1', 8000)
httpd = make_server(add[0], add[1], run_server)
print("Serving HTTP on server %s and port %s..." % (add[0], add[1]))
httpd.serve_forever()
# 不同URL返回不同的页面
from wsgiref.simple_server import make_server
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
# 获取url
url_path = environ['PATH_INFO']
if url_path == '/index':
return ['<h1>这是index页面</h1>'.encode('utf8'), ]
elif url_path == '/home':
return ['<h1>这是home页面</h1>'.encode('utf8'), ]
else:
return ['<h1>该网页无法显示</h1>'.encode('utf8'), ]
if __name__ == '__main__':
add = ('127.0.0.1', 8000)
httpd = make_server(add[0], add[1], run_server)
print("Serving HTTP on server %s and port %s..." % (add[0], add[1]))
httpd.serve_forever()
# 不同URL返回不同页面的升级版
rom wsgiref.simple_server import make_server
def url_index():
return ['<h1>这是index页面</h1>'.encode('utf8'), ]
def url_home():
return ['<h1>这是home页面</h1>'.encode('utf8'), ]
# 定义url和函数名的对应关系
URL_LIST = [
('/index', url_index),
('/home', url_home)
]
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
url_path = environ['PATH_INFO']
# 定义将要执行的函数
func_name = None
for i in URL_LIST:
if i[0] == url_path:
# 在定义号的列表中找到url_path对应的函数名
func_name = i[1]
break
# 判断URL_LIST是否能找到对应的函数名
if func_name:
# 返回url对应的函数名运行的结果
return func_name()
else:
return ['<h1>该网页无法显示</h1>'.encode('utf8'), ]
if __name__ == '__main__':
add = ('127.0.0.1', 8000)
httpd = make_server(add[0], add[1], run_server)
print("Serving HTTP on server %s and port %s..." % (add[0], add[1]))
httpd.serve_forever()
3. 使用wsgiref模块自定义静态页面框架
<!-- login.html -->
<!DOCTYPE html>
<html lang="en">
<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>login</title>
</head>
<body>
<form action="">
<div>
<label for="username">用户名:</label>
<input id="username" type="text" name="username">
</div>
<div>
<label for="password">密码:</label>
<input id="password" type="password" name="password">
</div>
</form>
</body>
</html>
from wsgiref.simple_server import make_server
def url_index():
return ['<h1>这是index页面</h1>'.encode('utf8'), ]
def url_home():
return ['<h1>这是home页面</h1>'.encode('utf8'), ]
# 定义登录页面函数
def url_login():
with open('login.html', 'rb') as f:
data = f.read()
return [data, ]
URL_LIST = [
('/index', url_index),
('/home', url_home),
('/login', url_login)
]
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
url_path = environ['PATH_INFO']
func_name = None
for i in URL_LIST:
if i[0] == url_path:
func_name = i[1]
break
if func_name:
return func_name()
else:
return ['<h1>该网页无法显示</h1>'.encode('utf8'), ]
if __name__ == '__main__':
add = ('127.0.0.1', 8000)
httpd = make_server(add[0], add[1], run_server)
print("Serving HTTP on server %s and port %s..." % (add[0], add[1]))
httpd.serve_forever()
4. 使用wsgiref模块自定义动态页面框架
<!-- time.html -->
<!DOCTYPE html>
<html lang="en">
<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>getNow</title>
</head>
<body>
<h1>当前时间戳是:@@##time##@@</h1>
</body>
</html>
import time
from wsgiref.simple_server import make_server
def url_index():
return ['<h1>这是index页面</h1>'.encode('utf8'), ]
def url_home():
return ['<h1>这是home页面</h1>'.encode('utf8'), ]
def url_login():
with open('login.html', 'rb') as f:
data = f.read()
return [data, ]
# 定义时间页面的函数
def url_time():
with open('time.html', 'rb') as f:
data = f.read()
time_str = str(time.time())
data_str = data.decode('utf8')
data_str = data_str.replace('@@##time##@@', time_str)
data_bytes = data_str.encode('utf8')
return [data_bytes, ]
URL_LIST = [
('/index', url_index),
('/home', url_home),
('/login', url_login),
('/time', url_time)
]
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
url_path = environ['PATH_INFO']
func_name = None
for i in URL_LIST:
if i[0] == url_path:
func_name = i[1]
break
if func_name:
return func_name()
else:
return ['<h1>该网页无法显示</h1>'.encode('utf8'), ]
if __name__ == '__main__':
add = ('127.0.0.1', 8000)
httpd = make_server(add[0], add[1], run_server)
print("Serving HTTP on server %s and port %s..." % (add[0], add[1]))
httpd.serve_forever()
5. 使用jinja2模块渲染模版页面
-
描述:使用jinja2模版渲染工具
-
说明:jinja2需要安装模块
-
安装:pip install jinja2
<!-- user.html -->
<!DOCTYPE html>
<html lang="en">
<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>usrInfo</title>
</head>
<body>
<h1>姓名:{{name}}</h1>
<h1>性别:{{sex}}</h1>
<h1>年龄:{{age}}</h1>
<h1>爱好:</h1>
<h3>
<ul>
{% for i in lst %}
<li>{{i}}</li>
{% endfor %}
</ul>
</h3>
</body>
</html>
import time
import jinja2
from wsgiref.simple_server import make_server
def url_index():
return ['<h1>这是index页面</h1>'.encode('utf8'), ]
def url_home():
return ['<h1>这是home页面</h1>'.encode('utf8'), ]
def url_login():
with open('login.html', 'rb') as f:
data = f.read()
return [data, ]
def url_time():
with open('time.html', 'r', encoding='utf8') as f:
data = f.read()
time_str = str(time.time())
data_str = data.replace('@@##time##@@', time_str)
data_bytes = data_str.encode('utf8')
return [data_bytes, ]
def url_user():
with open('user.html', 'r', encoding='utf8') as f:
data = f.read()
# 生成jinja2模板文件
template = jinja2.Template(data)
# 把数据填充到模板文件
res = template.render({
'name': 'yan',
'sex': 'boy',
'age': 20,
'lst': ['Linux', 'Python', 'MySQL']
})
res_bytes = res.encode('utf8')
return [res_bytes, ]
URL_LIST = [
('/index', url_index),
('/home', url_home),
('/login', url_login),
('/time', url_time),
('/user', url_user)
]
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
url_path = environ['PATH_INFO']
func_name = None
for i in URL_LIST:
if i[0] == url_path:
func_name = i[1]
break
if func_name:
return func_name()
else:
return ['<h1>该网页无法显示</h1>'.encode('utf8'), ]
if __name__ == '__main__':
add = ('127.0.0.1', 8000)
httpd = make_server(add[0], add[1], run_server)
print("Serving HTTP on server %s and port %s..." % (add[0], add[1]))
httpd.serve_forever()
6. 使用wsgiref模块结合连接数据库自定义页面框架
<!-- db.html -->
<!DOCTYPE html>
<html lang="en">
<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>dbInfo</title>
</head>
<body>
<h1>数据库中第一个用户名:{{username}}</h1>
<h1>数据库中第一个密码:{{password}}</h1>
</body>
</html>
import time
import jinja2
import pymysql
from wsgiref.simple_server import make_server
def url_index():
return ['<h1>这是index页面</h1>'.encode('utf8'), ]
def url_home():
return ['<h1>这是home页面</h1>'.encode('utf8'), ]
def url_login():
with open('login.html', 'rb') as f:
data = f.read()
return [data, ]
def url_time():
with open('time.html', 'r', encoding='utf8') as f:
data = f.read()
time_str = str(time.time())
data_str = data.replace('@@##time##@@', time_str)
data_bytes = data_str.encode('utf8')
return [data_bytes, ]
def url_user():
with open('user.html', 'r', encoding='utf8') as f:
data = f.read()
# 生成jinja2模板文件
template = jinja2.Template(data)
# 把数据填充到模板文件
res = template.render({
'name': 'yan',
'sex': 'boy',
'age': 20,
'lst': ['Linux', 'Python', 'MySQL']
})
res_bytes = res.encode('utf8')
return [res_bytes, ]
def url_db():
# 连接数据库获取第一条数据的用户名和密码
conn = pymysql.connect(host='localhost', port=3306, user='yy', password='123', db='day60', charset='utf8')
cursor = conn.cursor()
sql = 'select username,password from user;'
cursor.execute(sql)
# 获取数据库中第一个用户名和密码
username, password = cursor.fetchone()
with open('db.html', 'r', encoding='utf8') as f:
data = f.read()
template = jinja2.Template(data)
res = template.render({
'username': username,
'password': password
})
res_bytes = res.encode('utf8')
return [res_bytes, ]
URL_LIST = [
('/index', url_index),
('/home', url_home),
('/login', url_login),
('/time', url_time),
('/user', url_user),
('/db', url_db)
]
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
url_path = environ['PATH_INFO']
func_name = None
for i in URL_LIST:
if i[0] == url_path:
func_name = i[1]
break
if func_name:
return func_name()
else:
return ['<h1>该网页无法显示</h1>'.encode('utf8'), ]
if __name__ == '__main__':
add = ('127.0.0.1', 8000)
httpd = make_server(add[0], add[1], run_server)
print("Serving HTTP on server %s and port %s..." % (add[0], add[1]))
httpd.serve_forever()
7. 自定义Web框架
-
必备组件:
-
Socket服务端及应用程序
-
HTTP协议相关技术
-
HTML前端页面渲染
-
可用的数据库连接服务端
-
结合socket与应用程序的过程
-
A. 开发Socket套接字服务端,负责处理接收请求和响应的数据(Web服务端)
-
B. 根据不同的url实现不同的业务逻辑代码程序(处理数据)
-
C. 把已经处理好的数据填充到HTML页面中(字符串替换)
-
常见框架:
-
Django:全能型Web框架(带有B和C的功能,需要借助其他工具实现A)
-
Flask:轻量级的Web应用框架(带有B的功能,A和C需要使用其他工具)
-
Tornado:Facebook的开源异步Web框架(具备A、B、C的功能)
-
Bottle:与Flask类似的Web框架
-
web.py:一个小巧的Web框架
8. Django初识
-
版本选择:最新LTS版,Django-1.11.9
-
安装:
-
命令行安装:pip install django==1.11.9
-
Pycharm安装:Settings -> Project -> Project Interpreter -> 右边绿色+号 -> 搜索django -> 勾选Specify version -> 选择1.11.9 -> Install Package
-
手动安装:
-
官网下载页面https://www.djangoproject.com/download/
-
-
创建Django项目
-
命令行创建:django-admin startproject 项目名称 (默认会创建到命令行所在的目录下,可以使用cd命令切换目录再执行创建命令)
-
Pycharm创建:File -> New Project... -> Django -> 在Location后选择创建Django项目的目录 -> create
-
启动Django项目:
-
命令行启动:python manage.py runserver [127.0.0.1:8000]
-
默认地址是127.0.0.1,可以不用指定
-
默认端口是8000,可以不用指定
-
如果要使用其他端口号可以直接运行(python manage.py runserver 指定端口号)
-
Pycharm启动:使用PyCharm单独打开Django项目,点页面上方中部位置的绿色小三角,直接运行
-
Django目录结构
mysite/
├── manage.py # 管理文件
└── mysite # 项目目录
├── __init__.py
├── settings.py # 配置
├── urls.py # 路由 --> URL和函数的对应关系
└── wsgi.py # runserver命令就使用wsgiref模块做简单的web server
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"), # 静态文件存放位置
]
9. Django基础必备三件套
导入模块
from django.shortcuts import HttpResponse, render, redirect
HttpResponse
描述:内部传入一个字符串参数,返回给浏览器
def index(request):
# 业务逻辑代码块
return HttpResponse("OK")
render
-
描述:除request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数。将数据填充进模板文件,最后把结果返回给浏览器(类似于jinja2)
def index(request):
# 业务逻辑代码块
return render(request, "index.html", {'name': 'yan', 'sex': 'boy', 'age': 20,'hobby_lst': ['Linux', 'Python', 'MySQL']})
redirect
def index(request):
# 业务逻辑代码块
return redirect('https://www.baidu.com')
10. Django的简单应用
使用Django简单实现Bootstrap页面的登录校验
# 创建django项目并启动
django-admin startproject yy
cd yy
mkdir template
python manage.py 11111
# 访问
http://127.0.0.1:11111
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
<title>登录页面</title>
<style>
body {
background-color: #EEE;
}
#login {
margin-top: 150px;
}
#err {
color: red;
font-weight: bolder;
margin-top: 50px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div id="login" class="col-md-4 col-md-offset-4 col-xs-8 col-xs-offset-2">
<h3 class="text-center">请登录</h3>
<form class="form-horizontal" action="/index/" method="post">
<div class="form-group">
<label for="inputUsername" class="col-md-3 control-label">用户名</label>
<div class="col-md-9">
<input type="text" class="form-control" id="inputUsername" name="username"
placeholder="Username" autocomplete="off">
<div class="text-danger"></div>
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-sm-3 control-label">密码</label>
<div class="col-sm-9">
<input type="password" class="form-control" id="inputPassword" name="password"
placeholder="Password" autocomplete="off">
<div class="text-danger"></div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<div class="checkbox">
<label>
<input type="checkbox">记住我
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button id="index" type="submit" class="btn btn-primary btn-block">登录</button>
</div>
</div>
</form>
<div class="col-sm-offset-3 col-sm-9">
<h1 id="err">{{errMsg}}</h1>
</div>
</div>
</div>
<script src="/static/jQuery-3.2.1/jquery-3.2.1.min.js"></script>
<script>
function userLogin() {
$("#index").on("click", function () {
var flag = true;
$(".form-control").each(function () {
$(this).on("focus", function () {
$(".text-danger").text("");
$(".form-group").removeClass("has-error");
});
var inputVal = $(this).val();
var textMsg = $(this).parent().prev().text();
if (inputVal.length === 0) {
$(this).next().text(textMsg + "不能为空");
$(this).parent().parent().addClass("has-error");
flag = false;
return flag;
} else if (inputVal.length < 2) {
$(this).next().text(textMsg + "格式不合法");
$(this).parent().parent().addClass("has-error");
flag = false;
return flag;
}
});
return flag;
})
}
$(function () {
userLogin();
});
</script>
</div>
</body>
</html>
import pymysql
from django.conf.urls import url
from django.shortcuts import HttpResponse, render, redirect
def index(request):
err_msg = ''
if request.method == 'POST':
# 获取input框中输入的用户名和密码
name = request.POST.get('username')
pwd = request.POST.get('password')
# 获取数据库user表中的信息((id, username, password, age))
conn = pymysql.connect(host='localhost', port=3306, user='yy', password='123', db='day60', charset='utf8')
cursor = conn.cursor()
sql = 'select * from user;'
cursor.execute(sql)
data = cursor.fetchall()
# 判断用户名是否存在
for i in data:
if name == i[1]:
# 用户名存在判断对应的密码是否正确
if pwd == i[2]:
# 用户名和密码输入正确,页面跳转百度首页
return redirect('https://www.baidu.com/')
else:
# 密码错误,显示提示信息
err_msg = '密码错误'
return render(request, "index.html", {'errMsg': err_msg})
else:
# 用户名不存在,显示提示信息
err_msg = '用户不存在'
return render(request, "index.html", {'errMsg': err_msg})
return render(request, "index.html", {'errMsg': err_msg})
urlpatterns = [
url(r'^index/', index),
]