WEB后端服务第16天-Django第6天
一、请求与响应详解
1.1 request对象
1.1.1 扩展:mysql连接配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'advance1',
'HOST': '119.3.26.17',
'PORT': 3306,
'USER': 'root',
'PASSWORD': 'root',
'CHARSET': 'utf8'
}
}
默认情况下,需要安装mysqlclient, 我们也可以安装pymysql,但需要在主目录下要进行初始化安装。主工程目录下的_init_.py脚本中的内容:
import pymysql
pymysql.install_as_MySQLdb()
1.1.2 请求对象中的QueryDict属性
-
GET 查询参数
-
POST 表单参数, 包含post请求方法的参数
-
COOKIES 客户端中的当前domain的所有的Cookie信息
-
META wsgi中请求元信息(服务器环境信息、客户端请求信息)== environ
- REMOTE_ADDR 客户端IP地址
- PATH_INFO 请求路径
- REQUEST_METHOD 请求方法
- QUERY_STRING 查询参数
- CONTENT_TYPE 上传数据类型
-
FILES 上传的表单参数中所有的文件对象, MultiValueDict类对象, 文件对象的类型是InMemoryUploadedFile
-
session 会话中存储的数据(可以跨多个请求)
GET请求的案例
<!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>Regist2</title>
</head>
<body>
<p>
<form method="get" enctype="application/x-www-form-urlencoded">
<input name="name" placeholder="username">
<br>
<input name="phone" placeholder="phone">
<br>
爱好:
{% for love in loves %}
<input type="checkbox" name="love" value="{{ love }}"> {{ love }}
{% endfor %}
<br>
<button>提交</button>
</form>
</p>
<p>
GET请求的查询参数<br>
<ul>
{% for key, value in request.GET.items %}
{% ifnotequal key 'love' %}
<li>{{ key }}: {{ value }}</li>
{% endifnotequal %}
{% endfor %}
<li>
爱好:
{% for item in select_loves %}
{{ item }},
{% endfor %}
</li>
</ul>
</p>
</body>
</html>
# Create your views here.
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def regist(request, user_id=None):
loves = ['H5', 'Java', 'Python', 'Linux', 'Oracle', 'Cookie']
# 获取参数名相同的多个参数值
select_loves = request.GET.getlist('love')
return render(request, 'regist2.html', locals())
POST/PUT-ajax请求案例
<!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>Regist3</title>
</head>
<body>
<p>
<form method="post" enctype="application/x-www-form-urlencoded">
<input name="name" placeholder="username">
<br>
<input name="phone" placeholder="phone">
<br>
<button>提交</button>
</form>
</p>
<p>
<button onclick="up_ajax()">ajax发起put请求</button>
<script>
function up_ajax() {
data = {
name: '李成',
phone: '1991828272',
loves: ['唱', '跳', 'RAP', '篮球']
};
fetch('', {
method: 'PUT',
body: document.forms[0].serialize,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(response => response.text())
.then(html => {
document.write(html)
})
}
</script>
</p>
<p>
POST请求参数:
<ul>
{% for key, value in request.POST.items %}
<li>{{ key }}: {{ value }}</li>
{% endfor %}
</ul>
</p>
<p>
PUT的参数(body): {{ request.body }}
<br>
Content-Type: {{ request.content_type }};{{ request.encoding }}
</p>
</body>
</html>
@csrf_exempt
def regist(request, user_id=None):
print(request.POST)
print(request.method)
return render(request, 'regist3.html', locals())
POST实现文件上传案例
1.1.3 请求对象中的普通信息
- path 请求路径
- method 请求方法, GET/POST/PUT/DELETE
- content_type 数据类型, 如 请求头的Content-Type: text/html;charset=utf-8 , content_type只接数据类型 text/html。charset=utf-8的部分编码则由encoding存储
- encoding 数据编码,
- body 字节码数据, 一般接收上传的json数据, put上传的数据可以使用body来获取。
<!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>Regist</title>
</head>
<body>
<p>
<form method="post" enctype="application/x-www-form-urlencoded">
<input name="name" placeholder="username">
<br>
<input name="phone" placeholder="phone">
<br>
<input type="password" name="password" placeholder="password">
<br>
<input type="date" placeholder="生日">
<br>
<button>提交</button>
</form>
</p>
<p>
<button onclick="up_ajax()">ajax上传json数据</button>
<script>
function up_ajax() {
data = {
name: document.forms[0].name.value,
phone: document.forms[0].phone.value
};
fetch('', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
}).then(response => response.text())
.then(text =>{
document.write(text)
});
}
</script>
</p>
<p>
请求路径-path: {{ request.path }}
<br>
请求的URI(统一资源标识符): {{ request.get_raw_uri }}
<pre>
URL : 统一资源定位符, 资源的网络地址
URI: 统一资源标识符, 用于RESTful规范中,可以理解为URL
</pre>
</p>
<p>
请求方法: {{ request.method }}
<br>
content_type: {{ request.content_type }}
<br>
encoding: {{ request.encoding }}
<br>
content_params: {{ request.content_params }}
</p>
<p>
body: {{ request.body }}
</p>
</body>
</html>
github 仓库: git@github.com:disenQF/advanceDjango1.git
1.2 response对象
响应对象是视图函数返回的对象。由我们自己创建,当然,django很多快捷方法,如render()/redirect()快速生成response响应对象。
常用的响应类:
- HttpResponse
- HttpResponseRedirect
- JsonResponse
响应对象中包含的属性:
- content :响应的内容
- 如果是HttpResponse对象,则content可以是字节码也可以是字符串
- JsonResponse ,则content可以是dict字典
- status 响应的状态码
- content_type:响应的数据类型
设置响应头header
直接通过响应对象的字典特性来设置, 如 response[‘Content-Type’] = ‘image/jpeg’。
二、会话技术详解
一次会话(Session)或连接从浏览器的一个Request开始, 到服务器返回Response结束。可以在多个页面需要传递部分数据。
Django的Session的数据默认存储在django_session表中。但Session依赖于Cookie技术。客户端如果禁用了Cookie,则Session也会失效。
2.1 Cookie
def add_cookie(request):
# 生成token,并存储到 Cookie中
token = uuid.uuid4().hex
resp = HttpResponse('增加Cookie: token成功')
from datetime import datetime, timedelta
resp.set_cookie('token', token,
expires=datetime.now()+timedelta(minutes=2))
return resp
2.2 Session
def new_code(request):
# 生成手机验证码
# 随机产生验证码 : 大小写字母+数字
code_txt = 'Xab9'
phone = request.GET.get('phone')
# 保存到session中
request.session['code'] = code_txt
request.session['phone'] = phone
# 向手机发送验证码: 华为云、阿里云:短信服务
return HttpResponse('已向 %s 手机发送了验证码!' % phone)
2.3 Token
使用UUID产生。
def login(request):
phone = request.GET.get('phone')
code = request.GET.get('code')
if all((
phone == request.session.get('phone'),
code == request.session.get('code')
)):
resp = HttpResponse('登录成功')
token = uuid.uuid4().hex # 保存到缓存
resp.set_cookie('token', token)
return resp
return HttpResponse('登录失败,请确认phone和code!')
三、静态资源
- 绝对路径 【不推荐】
<link rel='sheetstyle' href='/static/css/my.css'>
- 相对路径
{% load static %}
<link rel='sheetstyle' href='{% static 'css/my.css' %}>
四、验证码
- 图片验证码
- 短信验证码
- 邮箱验证码
五、分页器
from django.core.paginator import Paginator,Page
def list(request):
# 获取页号
page_num = int(request.GET.get('page', 1))
# 获取查询条件
kw = request.GET.get(kw)
# 查询数据
datas = UserEntity.objext.filter(name__contains=kw).all()
paginator = Paginator(datas, 20)
pager = paginator.page(page_num)
return render(request, 'list.html', locals())
<form method='get'>
<input type='text' name='kw' value='{{ kw }}' >
<button>搜索</button>
</form>
<ul>
{% for u in pager.object_list %}
<li> {{u.name }} </li>
{% endfor %}
</ul>
<div id='page'>
{% for p in paginator.page_range %}
<span><a href="/list/?page={{ page }}&kw={{ kw }}">{{ p }}</a></span>
{% endfor %}
</div>
六、作业
1. 练习课堂代码并总结核心技术点
2. 实现注册登录功能
业务描述: 实现手机号登录,模拟发送短信验证码,如果手机号已存在,直接验证短信码,如果不存在,则先创建此用户,然后再验证,如果验证成功,则生成token,并保存到redis中(token:user_id)。
要求:
- 前后端的数据格式是json
- 提供完善信息接口, 接口参数必须提供token
3. 实现搜索功能
业务描述: 根据搜索关键字,模糊匹配商品名、类型名、商品描述,对查询的数据进行分页。
思考: 如果数据量超级多时,如何优化分页器