django框架
1 基于wsgiref定义自己的web框架.note
0 基于socket手写web框架.note
day01
1.web应用
web应用:
1
2
3web应用:是一种可以通过web访问的应用程序,最大的好处就是用户可以很容易访问应用程序,用户只需要在浏览器中打开网页,不需要安装其他软件。
cs架构
web应用:大部分是基于b/s架构的程序。web应用的优点
1
2
3
4
51.只需要一个浏览器即可。
2.网络应用程序通常耗费很少的用户硬盘空间。
3.不需要更新,所有的特性都是在服务器上执行,从而自动传达给用户端
4.和服务器端的网络产品很容易结合,如email功能和搜索功能
5.因为在网络浏览器窗口中运行,所以大部分情况下可以跨平台使用web应用的缺点
1
2
3
41.特别强调浏览器的适用性
2.如果连接出现问题,应用将不能访问
3.不能针对用户定制化,个性化
4.理论上可以检索任何用户的行为,这可能带来隐私安全问题总结
1
本质上:浏览器是一个socket客户端,服务器是一个socket服务端
2.http协议
什么是http协议
1
2
3http协议是超文本传输协议
是一个属于应用层的面向对像的协议
浏览器作为http的客户端,通过url向及web服务器发送所有请求,web服务器收到请求后,向客户端发送响应消息http协议的特性
1
2
3
4
5
6
71.基于tcp(传输层)/ip(网络层)协议之上的应用层协议
2.基于请求,响应模式
协议规定:请求从客户端发出,最后服务器端响应请求并返回
3.无状态保存:http协议自身不对请求和响应之间通信状态进行保存,也就是说http协议对于请求和发送不做持久化处理
注意:
由于http无状态保存,所以为了持久化处理,引入了cookie技术,有了cookie再用http协议通信,就可以管理状态了。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户请求,并受到客户的应答后,即断开连接。采用这种方式可以节省传输时间。http请求协议与响应协议
1
2
3
4
5
6
7
8
9
10http请求协议:
请求首行:
post(请求方式:POST/GET) /form/index HTTP/1.1
请求首部字段(请求头):
Host:127.0.0.1
Connection:keep-alive
Content-Type:application/x-www-form-urlencoded
Content-Length:16
请求体:
name = ueno&age = 331
2
3
4
5
6
7请求方式:get与post请求
1.GET提交的数据会放在url之后,以?分割url和传输数据,参数之间以&相连,如?name = test1&id = 1。
POST方法是把提交的数据放在http包的请求体中。
2.GET提交的数据大小有限制(因为浏览器的url的长度有限制),而POST方法提交的数据没有限制。
3.GET与POST请求在服务端获取请求数据方式不同响应协议
1
2
3
4
5
6
7状态行:协议版本 状态码 状态码描述
HTTP/1.1 200 OK
响应头部:
头部字段名:值 \r\n
响应正文:响应状态码
| 状态码 | 类别 | 原因短语 |
| —— | —————- | ————————– |
| 1xx | 信息性状态码 | 接受的请求正在处理 |
| 2xx | 成功状态码 | 请求正常处理完毕 |
| 3xx | 重定向状态码 | 需要进行附近操作以完成请求 |
| 4xx | 客户端错误状态码 | 服务器无法将处理请求 |
| 5xx | 服务器错误状态码 | 服务器处理请求出错 |url简介
1
2
3
4
5
6统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准支援你的地址。互联网上标准资源的地址,互联网上的每个文件都有一个唯一的url,它包含的信息支出文件的位置以及浏览器应该怎么处理它
格式:
协议://ip:端口(80) /路径?name=lqz$age=age=18
?之前的是请求路径,?之后的是请求数据部分
3.python中的web主流的框架(MVC)
1 | a:socket b:路由和视图匹配关系 c:模板渲染 |
6 内容总结
6 内容总结
django安装
1.几大部分
可以有多个APP
注意事项
命令运行django
django安装
1
2
3
4
5
6
7
8
9
10
11下载django
1.pip install django==1.11.9
创建项目
2.django-admin startproject 项目名
创建app
3.python manage.py startapp app01
运行项目
4.python mansge.py runserver 127.0.0.1:8001django文件目录
1
2
3
4
5
6manage.py 项目的入口,执行一些命令
settings 全局配置信息
urls 总路由,请求地址和视图函数的映射关系
migrations 数据库迁移的记录
models 数据库表模型
views 视图函数
day02
1.django中的app的概念
1 | 大学:项目 |
2.模板路径配置
1 | 1.templates文件夹 |
3.静态文件配置
1 | 1.STATIC_URL = '/static' 一般不要改 |
4.完整版登录功能
templates(模板)
1
2
3
4
5
6
71.login.html
1.1 action:提交到后台的地址三种写法:
http://127.0.0.1:8000/login
/login/
不写
1.2 method post方式
1.3 input type="submit" value= "提交" 或 buttonviews(视图层)
1
2
3
4
5
61.request.method 前台提交过来请求的方式POST/GET
2.request.POST(相当于字典) post形式提交过来的数据
3.request.POST.get('name') 通过key取值,取出列表的最后一个值
4.request.POST.getlist('name') 通过key取出列表的所有元素
注意:前台GET方式提交的数据,从request.GET字典中取值连接数据库(防止sql注入,推荐以下写法)
1
cur.execute('select * from user where name=%s and password=%s',[name,pwd])
5.GET请求和POST请求
1 | get:获取数据,页面,携带数据是不重要的数据(数据量有大小限制) |
6.新手三件套总结
1 | 1.render 返回页面,默认会templates里找,注意路径 |
7.pycharm连接数据库
1 | 参靠视频 |
8.orm介绍
1 | 1.orm即object relational mapping ,对象关系映射 |
9.orm创建表
1 | class BookList(models.Model): |
day3
一.orm操作表,记录
1.orm增加字段(table操作)
方法一
二
1 | models.py里面添加一个字段,一定要给增加的字段设为初始值,为null都可以,然后重新数据库迁移 |
2.orm删除字段
1 | models.py里面将字段删除,然后重新数据库迁移,注释也可以 |
3.orm修改字段
1 | models.py里面讲修改的字段,需要修改的东西写好,然后数据库迁移 |
4.orm查字段
1 | models.py里面看看就可以了 |
5.orm添加记录
1 | user=models.User.objects.create(name=name,password=pwd,address=addr) |
6.orm删除记录
1 | ret = models.User.objects.filter(id=id).delete() |
7.orm修改记录
1 | models.User.objects.filter(id=id).update(name=name, password=pwd, address=addr) |
8.orm查询记录
出来的是对象可以全部,可以点字段出想要的数据
数据在reder里面就已经替换完成
1 | ret = models.User.objects.all()列表 |
二.django中前端向后端发送请求后携带值得2种方式
方式一
1
2
3
4
5
6
7
8
9<form action="/updateuser/?id={{ user.id }}" method="post">
<p>用户名: <input type="text" name="name" value="{{ user.name }}"></p>
<p>密码: <input type="text" name="password" value="{{ user.password }}"></p>
<p>地址: <input type="text" name="addr" value="{{ user.address }}"></p>
<input type="submit" value="提交">
</form>
注意:后端如何取值
id = request.GET.get("id")方式二
1
2
3
4<p><input type="hidden" name="id" value="{{ user.id }}"></p>
注意:后端如何取值
id = request.POST.get("id")
三.django请求的生命周期
1 | 客户端发出请求 <--> web服务器(遵循wsgi协议) <--> 中间件<-->url路由层<-->视图层(views)<-->模型层<-->模板层 |
day4
一. 路由层
简单配置
1 | 1.第一个参数是正则表达式(如果要精准匹配:url(r'^admin/$', admin.site.urls)) |
无名分组
1 | 按位置传参 |
有名分组
1 | 按关键字传参 |
反向解析
是把一个
1 | 1.先命一个名: |
1 | 2.在模型层 |
1 | 3.在视图层 |
路由分发
创建APP
settings.py里面配置
app的视图函数要和路由一致
1 | 1. 在不同的app里创建urls.py |
名称空间
这样不用多此一举加入名称空间
1 | 1.url(r'^blog/',include('blog.urls',namespace='blog')), |
伪静态
1 | 路由:url(r'^book/(?P<id>\d+.html)',views.book), |
根路径响应到指定
day5
一.虚拟环境
1 | 1.虚拟环境的应用场景 |
1 | 2.通过virtualenv软件创建 |
1 | 3.在pycharm中创建虚拟环境 |
1 | 4.在pycharm下创建 新建项目 |
1 | 5.参数说明 |
二.django2和django1的路由的区别
1 | 1.django1和django2的路由区别 |
1 | path:传的路径,是准确路径 |
反斜杠(settings.py里面)
3.视图层之HttpResquest对象
1 | # 前台Post传过来的数据,包装到POST字典中 |
4.视图层之三件套
1 | 三件套:render,HttpResponse,redirect |
5.视图层之JsonResponse
1 | 导入: |
6.CBV和FBV类的视图还是函数的视图
1 | 基于类的视图 |
7.简单的文件上传功能
1 | 1.模板层 |
1 | 2.视图层 |
day6
1.模板层
1 | 1.解释视图如何工作的 |
1 | 2.为什么使用模板 |
1 | 3.原始视图函数和django模板修改的视图函数 |
2.模板语法之变量
1 | 模版语法重点: |
1 | 1.html部分 |
1 | 2.视图部分 |
3.模板语法之过滤器
1 | 1.html部分 |
4.模板语法之标签
1 | 1.html部分 |
5.模板语法之自定义过滤器
1 | ***标签不能用在if判断中,过滤器,可以用在if判断中 |
1 | 2.实例html部分 |
6.模板语法之自定义标签
1 | 自定义标签: |
1 | 2.实例之html部分 |
7.模板的导入(重复使用)
1 | 1.什么是模板的导入 |
8.模板的继承
1 | 注意:模板继承的时候,可以先将需要的数据,查询出来,然后通过local(),将数据拿到前端页面渲染,在后台渲染完毕后,返回到前台, |
1 | eg: |
1 | 1.什么是模板的继承 |
9.静态文件相关
1 | 方式一:写死静态文件的路径 |
1 | 方式二:通过反向查找拼接路径 |
1 | 方式三:通过反向查找 |
day7
1.单表操作
1 | 1.数据库迁移命令 |
1 | 2.查询的api(接口)********** |
1 | 删除: |
1 | 修改: |
1 | 查询:********非常重要********** |
1 | 查询:基于双下划线的模糊查询 |
day8
1 | 1.django终端打印sql语句 |
1 | 2.创建模型 |
1.一对多的增删改
1 | 1.一对多的新增数据 |
2.多对多的增删改
1 | 1.多对多的增删改 |
3.一对一的增删改
1 |
4.基于对象的跨表查询
1 | 1.一对一 |
1 | 2.一对多 |
1 | 3.多对多 |
5.基于双下划线的连表查询
1 | 1.一对一:基于双下划线的查询(连接查询inner left right union) |
1 | 2.基于双下划线的一对多的连表查询(出版社 -- book) |
1 | 3.基于双下划线的多对多的连表查询(book -- author) |
1 | 4.连续跨表(进阶版) |
6.聚合查询aggregate –(Avg, Count, Max, Min, Sum)
1 | # 聚合查询aggregate 是queryset终止子句 |
7.分组查询annotate ()
1 | 总结终极版本 |
1 | # 分组查询annotate |
8.F函数:同一张表中的2个字段作比较
1 | 1.导入此模块 |
1 | # F函数 |
9.Q函数:与或非(&|~)
1 | 1.导入此模块 |
1 |
|
day9
1.ORM常用字段
1 |
2.ORM不常用的字段
1 | AutoField(Field) |
3.ORM和mysql中对应的字段关系
1 | 对应关系: |
4.ORM字段参数
1 | null |
5.关系字段
1 | 1.ForeignKey |
1 | 2.OneToOneField |
1 | 3.ManyToManyField |
6.元信息
1 | ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下: |
1 | 实例: |
7.自定义字段(了解)
1 | 自定义char类型字段: |
8.多对多关联关系三种创建方式
1 | 方式一:自行创建第三张表 |
1 | 方式二:通过ManyToManyField自动创建 |
1 | 方式三:设置ManyToManyField并指定自己创建的第三张表 |
1 | 注意: |
day10
1.inclusion_tag
1 | 1.作用 |
2.defer/only(数据库优化)
1 | defer---->除了指定字段之外 |
3.事务(原子性操作)
1 | from django.db import transition |
4.choice
1 | 模型表中某个字段,可以指定choice,用在选择不经常变的情况,经常变,尽量用数据库 |
day11
1.ajax组件
1 | 1.什么是ajax |
1 | 2.如何用:基本使用 |
2.通过ajax上传文件
1 | 1.模板层 |
3.基于ajax提交json格式的数据
1 | 1.模板层 |
1 | 重点: |
4.基于ajax如何实现用户认证通过后的页面转跳
1 | 1.模板层 |
1 | 2.模板order |
1 | 3.视图 |
4.视图函数通过装饰器将json数据格式自动转成python中的数据类型
1 | import json |
1 | 注意: |
5.ajax路径相关问题(**)
1 | js得到当前页面的url信息方法 |
1 | ajax注意提交数据和form表单的冲突 |
6.ajax获取响应头以及自定义请求头
1 | <!DOCTYPE html> |
7.ajax传json格式字典,如何通过验证(***)
1 | let dic = { |
8.ajax静态刷新
1 | 1.html |
1 | 2.jquery |
9.简单的控制上传文件的方法
1 | accept='image/*' |
day12
1.分页器组件(*)
1 | 1.批量插入 |
1 |
|
1 | 3.前五后五进行分页:(视图层) |
1 | 1.模板层: |
day13
1.Forms校验功能组件
1.校验字段的功能
1
2
3
41.前端传过来的数据,通过post或者get,或者body里面取出来,生成字典类型
2.将自定义的UserForms类实例化,同时将字典传入该类中,生成一个form的对象
3.执行form.is_valid()进行字段的校验
4.详情见实例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
211.模板层
<form action="" method="post" novalidate="false">
{% csrf_token %}
<div>
<label for="user">用户名</label>
<p><input type="text" name="name" id="name"></p>
</div>
<div>
<label for="pwd">密码</label>
<p><input type="password" name="pwd" id="pwd"></p>
</div>
<div>
<label for="r_pwd">确认密码</label>
<p><input type="password" name="r_pwd" id="r_pwd"></p>
</div>
<div>
<label for="email">邮箱</label>
<p><input type="text" name="email" id="email"></p>
</div>
<input type="submit">
</form>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
332.视图层
# forms组件
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
wid_01=widgets.TextInput(attrs={"class":"form-control"})
wid_02=widgets.PasswordInput(attrs={"class":"form-control"})
class UserForm(forms.Form):
name=forms.CharField(max_length=32,
widget=wid_01
)
pwd=forms.CharField(max_length=32,widget=wid_02)
r_pwd=forms.CharField(max_length=32,widget=wid_02)
email=forms.EmailField(widget=wid_01)
tel=forms.CharField(max_length=32,widget=wid_01)
def register(request):
if request.method=="POST":
form=UserForm(request.POST)
if form.is_valid():
print(form.cleaned_data) # 所有干净的字段以及对应的值
else:
print(form.cleaned_data) #
print(form.errors) # ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors.get("name")) # ErrorList ["错误信息",]
return HttpResponse("OK")
form=UserForm()
return render(request,"register.html",locals())1
2
3
4
5
64.form对象常用的方法和属性
form.cleaned_data --所有校验通过的字段,以及对应的值
form.errors -- 如果有校验不通过的字段,则会返回一个ErrorDict:{"校验错误的字段":["错误信息",]}
form.errors.get("name") --ErrorList ['错误信息'] --一般我们取第一个错误信息1
2
3
45.for循环form对象,得到字段对象f,form里面的类中一定重写了__iter__方法
f.lable 获取字段的标签
f.name 获取字段的名字
f.errors 获取字段的错误列表,一般我们取第一个字段作为错误信息渲染到页面2.渲染标签的功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
311.方式一:直接用form对象进行渲染,有较强的灵活性,但是代码量多
<h3>注册页面</h3>
<div class="container">
<div class="row">
<div class="col-md-6 col-lg-offset-3">
<form action="" method="post" novalidate="false">
{% csrf_token %}
<div>
<label for="">用户名</label>
{{ form.name }} --最终会被解析成input标签
</div>
<div>
<label for="">密码</label>
{{ form.pwd }}
</div>
<div>
<label for="">确认密码</label>
{{ form.r_pwd }}
</div>
<div>
<label for=""> 邮箱</label>
{{ form.email }}
</div>
<input type="submit" class="btn btn-default pull-right">
</form>
</div>
</div>
</div>1
2
3
4
5
6
7
8
9
10
11
12
132.方式二:推荐使用
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div>
<label for="">{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
<input type="submit" class="btn btn-default pull-right">
</form>1
2
3
4
5
6
7
8
93.方式三:代码量少但是可拓展性变弱
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-default pull-right">
</form>3.渲染错误信息的功能
1
2
3
4
5
6
7
8
9
10
11
12
13
141.视图
def register(request):
if request.method=="POST":
form=UserForm(request.POST)
if form.is_valid():
print(form.cleaned_data) # 所有干净的字段以及对应的值
else:
print(form.cleaned_data) #
print(form.errors) # ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors.get("name")) # ErrorList ["错误信息",]
return render(request,"register.html",locals())
form=UserForm()
return render(request,"register.html",locals())1
2
3
4
5
6
7
8
9
10
11
12
132.模板:field.errors.0就是错误信息的第一个
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div>
<label for="">{{ field.label }}</label>
{{ field }} <span class="pull-right" style="color: red">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<input type="submit" class="btn btn-default">
</form>4.组件的参数配置
1
2
3
4
5
6
7class Ret(Form):
name = forms.CharField(max_length=10, min_length=2, label='用户名',
error_messages={'required': '该字段不能为空', 'invalid': '格式错误', 'max_length': '太长',
'min_length': '太短'},
widget=widgets.TextInput(attrs={'class':'form-control'}))
pwd = forms.CharField(max_length=10, min_length=2, widget=widgets.PasswordInput(attrs={'class':'form-control'}))
email = forms.EmailField(label='邮箱', error_messages={'required': '该字段不能为空', 'invalid': '格式错误'})5.局部钩子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
def clean_name(self):
val=self.cleaned_data.get("name")
ret=UserInfo.objects.filter(name=val)
if not ret:
return val
else:
raise ValidationError("该用户已注册!")
def clean_tel(self):
val=self.cleaned_data.get("tel")
if len(val)==11:
return val
else:
raise ValidationError("手机号格式错误")6.全局钩子
1
2
3
4
5
6
7
8
9
10
11
12def clean(self):
pwd=self.cleaned_data.get('pwd')
r_pwd=self.cleaned_data.get('r_pwd')
if pwd and r_pwd:
if pwd==r_pwd:
return self.cleaned_data
else:
raise ValidationError('两次密码不一致')
else:
return self.cleaned_data7.注意事项(***)
1
2
3
4
5
61.form表单的name属性值应该与forms组件字段名称一致
2.form除了可以校验前端传过来的数据,也可以校验数据库的数据
比如数据库为空的字段,可以过滤掉
3.如果前台是ajax传过来的json格式对象,那么我们返回时一定要返回json格式Httpresponse,自然对应模板中通过dom操作,渲染到模板中。8.实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72视图层
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
class MyForm(forms.Form):
name = forms.CharField(max_length=10, min_length=3, label='用户名',
error_messages={'max_length': '最长是10', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.TextInput(attrs={'class': 'form-control name'}))
password = forms.CharField(max_length=20, min_length=3, label='密码',
error_messages={'max_length': '最长是20', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.PasswordInput(attrs={'class': 'form-control password'}))
re_password = forms.CharField(max_length=20, min_length=3, label='请确认密码',
error_messages={'max_length': '最长是20', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.PasswordInput(attrs={'class': 'form-control re_password'}))
sex = forms.IntegerField(max_value=3, min_value=1, label='性别',
error_messages={'max_length': '最长是3', 'min_length': '最短是1', 'required': '这个必须填'},
widget=widgets.NumberInput(attrs={'class': 'form-control sex'}))
email = forms.EmailField(label='邮箱', widget=widgets.EmailInput(attrs={'class': 'form-control email'}),
error_messages={'required': '这个必须填', 'invalid': '不符合邮箱格式'})
def clean_name(self):
name = self.cleaned_data.get('name')
print(name)
from app01.models import User
name_list = User.objects.all().values('name')
lis = [v['name'] for v in name_list]
if name in lis:
raise ValidationError('用户名重复')
return name
def clean(self):
password = self.cleaned_data.get("password")
re_password = self.cleaned_data.get("re_password")
if password == re_password:
return self.cleaned_data
else:
raise ValidationError('两次输入的密码不一致')
def register(request):
if request.method == 'GET':
my_form = MyForm()
print(type(my_form))
for i in my_form:
print(i)
print(i.label)
print(i.name)
print(i.errors)
elif request.method == 'POST':
import json
print(request.GET)
print(request.POST)
print(request.body)
print(request.META)
print(json.loads(request.body))
my_form = MyForm(json.loads(request.body))
if my_form.is_valid():
my_form.cleaned_data.pop("re_password")
User.objects.create(**my_form.cleaned_data)
dic = {'status': True}
return JsonResponse(dic)
else:
global_error = my_form.errors.get('__all__')
if global_error:
my_form.errors['all'] = [global_error[0]]
my_form.errors.pop("__all__")
return JsonResponse(my_form.errors)
return render(request, 'register.html', locals())1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105模板层
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>注册</title>
<link rel="stylesheet" href="/static/utils/bootstrap-3.3.7-dist/css/bootstrap.css">
<script src="/static/utils/jquery-3.3.1.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 col-lg-offset-3">
<div>
<form class="form-horizontal">
{% for foo in my_form %}
<div class="form-group ">
<label for="inputEmail3" class="col-sm-2 control-label">{{ foo.label }}</label>
<div class="col-sm-10 mm" id="{{ foo.auto_id }}">
{{ foo }}
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-default" id="btn">注册</button>
<span id="id_all"></span>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
<script>
$('#btn').click(function () {
let dic = {
"name": $('.name').val(),
"password": $('.password').val(),
"re_password": $('.re_password').val(),
"sex": $('.sex').val(),
"email": $('.email').val()
};
let json_dic = JSON.stringify(dic);
console.log(dic);
$.ajax({
url: '/register/',
type: 'post',
contentType: 'application/json',
data: json_dic,
dataType: 'json',
success: function (data) {
console.log(data);
$.each(data, function (i, obj) {
if (i === 'status') {
location.href='http://www.baidu.com'
}
console.log(i);
console.log(i, obj);
let $span = $('<span></span>');
$span.text(obj[0]);
res = '#id_aa'.replace('aa', i);
console.log(res);
$span.appendTo(res)
})
}
})
});
$('#id_name .name').mouseout(function () {
if ($(this).val()) {
let name_dic = {'name': $(this).val()};
let json_dic = JSON.stringify(name_dic);
$.ajax({
url: '/register/',
type: 'post',
contentType: 'application/json',
data: json_dic,
dataType: 'json',
success: function (data) {
if ($('.myname').length > 0) {
console.log('jjj')
} else {
let $span = $('<span></span>');
console.log(data, 'mmmmmmmm');
$span.text(data.name[0]);
$span.addClass('myname');
$span.appendTo($('#id_name'));
setTimeout(function () {
$span.remove();
}, 3000)
}
}
})
} else {
console.log($(this).val())
}
})
</script>
</html>
day14
1.cookie组件
1.会话跟踪技术
1
2
3
4
51.因为http协议是无状态协议,也就是说每个请求都是相互独立的!
这样会导致每次请求过来都是一个全新的会话,无法知道上一次会话的是谁,但是在
同一个会话中,应该是数据共享的,所以就有了cookie和session来完成
2.seesion底层依赖的是cookie技术2.cookie简介
1
2
3
4
5
61.什么是cookie
cookie的本质就是key-value结构,类似于python中的字典
客户端浏览器第一次发送请求(没有cookie)-->服务端判断是否有cookie---没有---就生成一个cookie--返回给客户端浏览器--客户端浏览器保存这个cookie
客户端浏览器第二次发送请求(有之前存的cookie)-->服务器判断是否有cookie-->有cookie,服务器会识别数据,最终返回给客户端数据3.cookie规范
1
2
31.cookie大小上限4kb
2.一个服务器最多在客户端保存20个cookie
3.一个浏览器最多保存300个cookie4.cookie的覆盖
1
2
3如果服务端发送重复cookie那么就会覆盖原有的cookie
例如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A;第二请求服务器端发送的是:Set-Cookie: a=AA,那么客户端只留下一个Cookie,即:a=AA。5.在浏览器中查看cookie
1
浏览器中按F12,点network---cookie就能看到
2.django中如何使用cookie
1.获取cookie
1
2
3
4
5
6
7request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
name=request.COOKIES.get('name')
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间2.设置cookie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25rep = HttpResponse(...)
rep = render(request, ...)
rep.set_cookie(key,value)
格式:Set-Cookie: name:zhang
rep.set_signed_cookie(key,value,salt='加密盐')
格式:Set-Cookie: name=zhang:1gPsDw:kPYWmlBNjZ7YXCSKT50nb1ldLjk;
参数:
#key---- 键
#value='', 值
#max_age=None, 超时时间 cookie需要延续的时间(以秒为单位)如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止
#expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
#path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
#domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取
#secure=False, 浏览器将通过HTTPS来回传cookie
#httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)3.删除cookie
1
2
3
4
5
6
def delete_cookie(request):
obj = HttpResponse('ok')
# 指定删除名字是name的cookie
obj.delete_cookie('name')
return obj4.登录认证装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37# 登录认证装饰器
def login_auth(func):
def inner(request, *args, **kwargs):
# 拿到之前访问的路径
# 这个不行,因为取不到数据部分
# url=request.path
url = request.get_full_path()
is_login = request.COOKIES.get('is_login')
if is_login:
res = func(request, *args, **kwargs)
return res
else:
return redirect('/login/?next=%s' % url)
return inner
# 新的login
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
next = request.GET.get('next')
name = request.POST.get('name')
pwd = request.POST.get('pwd')
if name == 'lqz' and pwd == '123':
if next: #判断是否存在next,存在则返回之前的页面,反之返回shop页面,并生成一个新的cookie
obj = redirect(next)
else:
obj = redirect('/shopping/')
obj.set_cookie('is_login', True)
return obj
else:
return HttpResponse('用户名或密码错误')
3.session组件(一定要做数据库迁移)
1.session的由来
1
2
3
4
51.Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。
2.session必须和cookie连用2.django中session相关方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1']
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 会话session的key
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")
# 删除当前会话的所有Session数据(只删数据库)
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie(数据库和cookie都删)。
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。1
2
3思考,如果第二个人再次再同一个浏览器上登录,django-session表会怎样?
会覆盖之前session,之前用户的登录信息失效1
2**************session的配置
不但能放到数据库,还能放到文件中,redis(内存数据库)3.基于session的登录验证装饰器(FBV)
1
2
3
4
5
6
7
8
9
10
11# 基于session写一个登陆认证装饰器,登陆之后才能查看订单页面,购物页面
def auth_login(func):
def inner(request, *args, **kwargs):
url = request.get_full_path()
if request.session.get('is_login'):
res = func(request, *args, **kwargs)
return res
else:
return redirect('/login/?next=%s' % url)
return inner1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
name = request.POST.get("name")
password = request.POST.get("password")
next = request.GET.get('next')
if name == 'zhang' and password == '123':
if next:
obj = redirect(next)
else:
obj = redirect('/shopping/')
request.session['is_login'] = True
return obj
else:
return HttpResponse('账号或密码错误')
def shopping(request):
return HttpResponse('我是购物页面')
def order(request):
return HttpResponse('我是订单页面')4.登录认证装饰器(CBV)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56from django.shortcuts import render, HttpResponse, redirect
from django.views import View
from django.utils.decorators import method_decorator
from app01.models import User, OrderMsg
from django.http import JsonResponse
# Create your views here.
def auth(func):
from functools import wraps
def inner(request, *args, **kwargs):
url = request.get_full_path()
if request.session.get('id'):
res = func(request, *args, **kwargs)
return res
else:
return redirect('/login/?next=%s' % url)
return inner
class Login(View):
def get(self, request):
return render(request, 'login.html')
def post(self, request):
name = request.POST.get('name')
password = request.POST.get('password')
res = User.objects.filter(name=name, password=password).first()
if res:
url = request.GET.get('next')
print(request.GET)
request.session['name'] = res.name
request.session['id'] = res.pk
if url:
return redirect(url) ---#这地方有问题
else:
return redirect('/order/')
else:
return JsonResponse({'data': '用户名或密码错误', 'status': '100'})
class Order(View):
def get(self, request):
id = request.session.get('id')
msg = OrderMsg.objects.filter(user_id=id).all().values('name', 'price')
lis = {'status': '101', 'data': [{i.get('name'): i.get('price')} for i in msg]}
return JsonResponse(lis, safe=True, json_dumps_params={'ensure_ascii': False})
def post(self, request):
return HttpResponse('ok')1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>登录</title>
{% load static %}
<script src="{% static '/utils/jquery-3.3.1.js' %}"></script>
</head>
<body>
<form>
用户名:<input type="text" name="name" class="name">
密码:<input type="text" name="password" class="password">
<button type="button" id="btn">提交</button>
<span class="ss"></span>
</form>
</body>
<script>
$('#btn').click(function () {
let msg = {
'name': $('.name').val(),
'password': $('.password').val()
};
$.ajax({
url: '/login/',
type: 'post',
data: msg,
dataType: 'json',
success: function (data) {
console.log(data);
if (data.status === '100'){
$('.ss').text(data.data);
}
if (data.status === '101') {
location.href ='http://127.0.0.1:8234/order/';
}
}
})
})
</script>
</html>
day15
1.中间件
1 | 1.什么是中间件 |
2.自定义中间件
1 | 1.导入 |
1 | 注意: |
3.中间件的方法(最重要前2个)
1 | -process_request |
4.csrf:跨站请求伪造
1 | 比如:转账请求:transfer?to=lqz&count=1000 |
1 | 如何防范: |
1 | 验证原理: |
1 | 如何使用: |
5.csrf:局部禁用,局部使用(CBV)
1 | 1.局部禁用:全局就得使用 |
1 | 注意:**** |
6.csrf:局部禁用,局部使用(FBV)
1 | 用装饰器:from django.views.decorators.csrf import csrf_exempt,csrf_protect |
day16
1.auth组件
1 | 1.什么是auth组件 |
is_superuser是0普通用户,1超级用户
干了3件事生成一个随机字符串,把随机字符串写到cookie里,再写道session的字典里
以后在任意视图可以调用user的方法
auth中间件
2.auth组件常用的功能
1 | 1.auth验证功能 --authenticate |
1 | 2.auth登录功能 --login |
1 | 3.auth注销功能 --logout |
1 | 4.auth的登录认证装饰器 |
1 | 5.auth创建用户 --create_user/create_superuser |
1 | 6.auth校验密码 ---check_password |
1 | 7.auth修改密码 ---set_password |
1 | 8.auth判断当前用户是否通过认证 ---is_authenticated(调用了login方法) |
1 | 9. |
orm删除
3.扩展默认的auth_user表(增加一个字段)
1 | 方式一:使用一对一关联 |
1 | 方式二:使用类继承AbstractUser,因为user模块也是继承了AbstractUser |
重构后导入自己的
4.auth使用login_required如何重定向回去
1 | # 需要登录的视图函数 |
1 | 1.ajax按照上面的方式重定向 |